你正在使用的Go版本是什么(go version
)?
$ go version
go version go1.17 linux/amd64
这个问题在最新版本中是否重现?
是的。
你正在使用什么操作系统和处理器架构(go env
)?go env
输出
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/jano7/.cache/go-build"
GOENV="/home/jano7/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/jano7/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/jano7/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/jano7/Documents/prog/golang/tmp/sortwords/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2259433300=/tmp/go-build -gno-record-gcc-switches"
你做了什么?
package main
import (
"fmt"
"golang.org/x/text/collate"
"golang.org/x/text/language"
)
func main() {
words := []string{"čaj", "auto", "pot", "márny", "kľak", "chyba", "drevo",
"cibuľa", "džíp", "džem", "šum", "pól", "čučoriedka", "banán", "čerešňa",
"červený", "klam", "čierny", "tŕň", "pôst", "hôrny", "mat", "chobot",
"cesnak", "kĺb", "mäta", "ďateľ", "troska", "sýkorka", "elektrón",
"fuj", "zem", "guma", "hora", "gejzír", "ihla", "pýr", "hrozno",
"jazva", "džavot", "lom"}
c := collate.New(language.Slovak)
c.SortStrings(words)
fmt.Println(words)
}
$ go run sort_accented_words.go
[auto banán cesnak cibuľa čaj čerešňa červený čierny čučoriedka ďateľ drevo džavot džem
džíp elektrón fuj gejzír guma hora hôrny hrozno chobot chyba ihla jazva kľak klam kĺb lom
márny mat mäta pól pot pôst pýr sýkorka šum tŕň troska zem]
这个解决方案并不是100%正确(但与其他语言(如Java、C#或Python)相比仍然相当不错)。
从我测试过的语言来看,Raku和Go提供了最接近的解决方案。(Raku处理重音符号正确,但对双音节词处理失败。)
以下是斯洛伐克语中字符的正确顺序:
a, á, ä, b, c, č, d, ď, dz, dž, e, é, f, g, h, ch, i, í, j, k, l, ĺ, ľ, m, n, ň, o, ó, ô, p, q, r, ŕ, s, š, t, ť, u, ú, v, w, x, y, ý, z, ž
注意普通字符总是在重音字符之前。所以单词ďateľ应该在drev后面,序列kľak klam kĺb应该是klam kĺb kľak,márny mat mäta应该是mat márny mäta,pól pot pôst应该是pot pól pôst,以及tŕň troska应该是troska tŕň。
带有双音节词ch的单词是正确的。(dž双音节词可能也很好。不是100%确定,因为有一个关于ď的问题。)
所以正确的顺序应该是:
$ go run sort_accented_words.go
[auto banán cesnak cibuľa čaj čerešňa červený čierny čučoriedka drevo ďateľ džavot džem
džíp elektrón fuj gejzír guma hora hôrny hrozno chobot chyba ihla jazva klam kĺb kľak lom
mat márny mäta pot pól pôst pýr sýkorka šum troska tŕň zem]
7条答案
按热度按时间nvbavucw1#
Go语言的字符串排序并不是按照任何语言中事物排序的方式。它只是对utf8编码的原始字节进行排序。
你可能需要使用golang.org/x/text/collate库。有关示例,请参阅https://webdevstation.com/posts/how-to-sort-strings-with-go-alphabetically-in-any-language/。
rkttyhzu2#
对不起,你正在使用那个。我想这是
x/text/collate
的一个bug?9cbw7uwe3#
是的,看起来像是
x/text/collate
。kxeu7u2r4#
cc @mpvl
0kjbasz65#
你好,
我尝试研究了一下这个问题,但没有深入到足够深的兔子洞中去修复它。以下是我发现的内容(系好安全带,这是一次漫长的旅程):
首先我想从这个事实开始,字母表在这里似乎被正确定义了。所以这不是问题所在。
collate pkg 使用这个unicode算法对单词进行排序:
主要算法有四个步骤:
字母
č
可以正确排序。č
,算法会产生一个包含一个排序元素(0x402c3c20
)的数组。5662
、次权重32
、三级权重2
。[22 30 0 0 0 32 0 0 2]
字母
ď
不会正确排序。ď
,算法会产生一个包含一个排序元素(0xe0000a83
)的数组。代码。0x402c6220
)和重音符号 (0xae604102
)。代码。d
(没有重音符号)具有主权重5681
、次权重32
、三级权重2
。0
、次权重65
、三级权重2
。[22 49 0 0 0 32 0 65 0 0 2 2]
d
视为几乎相同的与ď
。[d da dat d ď ďat]
,它将被视为等于[d ď da dat ďat dr]
,这就好像d'
==d
一样。更深入的例子
对于
ďat
的排序字符串是:[22 49 21 239 24 22 0 0 0 32 0 65 0 32 0 32 0 0 2 2 2 2]
:|-----------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------------|------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |------- |
hsgswve46#
@ameowlia,感谢你的分析!遗憾的是,我对
x/text/collate
的了解非常有限,所以我不确定我能否提供有用的建议来指导接下来的工作。不过,我有一个问题:元素拆分问题是否存在于Unicode TR10算法本身,还是Go实现偏离了该算法?(如果问题存在于TR10算法本身,那么Go项目不能单方面解决它...)
qf9go6mv7#
你好@bcmills,
Unicode TR10算法中是否存在元素拆分问题,还是Go实现与算法有所偏离?
🐛 我认为这是Go中的一个bug
在第7.5节中,它使用了以下示例:
... the following incorrect ordering would result: "aa" < "àa" < "ab"
... the following correct ordering would result: "aa" < "ab" < "àa"
这正是我上面描述的错误结果。我认为这一节描述的是另一个(但可能相关的问题,而不是我们在这里遇到的问题。然而,我的观点是,文档明确指出我们得到的结果是不正确的。
🇸🇰 它特别提到了
ch
ch
在斯洛伐克语中被认为是一个字符,排在h
之后,排在i
之前。在第3.3.3节缩略词中,文档说:同样,当序列ch被视为单个双字母时,例如在斯洛伐克语中,它被表示为从两个字符到单个排序元素的Map,如下所示。...
在这个例子中,排序元素[.1D19.0020.0002]的主权重比单独的字母h的主权重大一,因此ch将排在h之后,i之前。这个例子展示了对排序元素Map进行定制以将字母作为单个单元的权重序列的结果。
上面我说问题出在
d' does not have a different primary value from d
上。我认为这一节的文档有助于证实不同的字母应该具有不同的主值。而且因为斯洛伐克语将带有重音的字母视为不同的字母,所以它们应该具有不同的主值。👀 Go哪里出错了?
"aa" < "ab" < "àa"
、a
、à
和b
都需要不同的主值。❓ 开放性问题