“字符串”有原因吗?EqualFold'不先做长度比较吗?

Is there a reason why `strings.EqualFold` does not do a length comparison first?

提问人:z11i 提问时间:11/16/2023 最后编辑:iczaz11i 更新时间:11/16/2023 访问量:89

问:

比较不区分大小写的字符串的常见做法是首先显式检查长度:

if len(a) == len(b) && strings.EqualFold(a, b) { ... }

这似乎是一种解决方法,因为当前实现仅在耗尽两个输入字符串中的任何一个时才进行长度检查。

是否有原因不首先进行长度检查,无论是性能方面还是其他方面?

字符串 Go Unicode

评论

3赞 Volker 11/16/2023
形式上,字符串可以是 EqualFold,而以字节为单位的长度不同。所以是的,这是有原因的。“将字符串与不区分大小写进行比较的常见做法”可能很常见,但它是完全错误的(因为它对 Unicode 的工作方式做出了毫无根据的假设)。
0赞 Volker 11/16/2023
请注意,在一般情况下,(正确的)Go 版本的长度检查不会比较输入字符串的长度。有关示例,请参阅测试用例,例如 cs.opensource.google/go/go/+/refs/tags/go1.21.4:src/strings/...

答:

6赞 icza 11/16/2023 #1

简短的回答是因为 2 个字符串在 Go 中可能具有不同的长度,但在简单的 Unicode 大小写折叠下仍然相等(因此首先进行长度比较并不能确定大小写折叠是否相等)。

更长的答案是:Go 将字符串作为 UTF-8 字节存储在内存中,内置的 len() 函数以 UTF-8 编码报告字节数。UTF-8 是一种可变长度的字符编码:它可以对单个 Unicode 代码点使用不同数量的字节,因此匹配的大小写折叠代码点可以在 UTF-8 中使用不同数量的字节。

请参阅一个示例来证明这一点:

s1, s2 := "\u017F", "\u0073"
fmt.Println(s1, s2)

fmt.Println(len(s1), len(s2), strings.EqualFold(s1, s2))

这将输出(在 Go Playground 上尝试):

ſ s
2 1 true