如何在 Go 中获取字符串的字符数?
例如,如果我有一个字符串,"hello"该方法应该返回5. 我看到len(str)返回的字节数,而不是字符的数量,以便len("£")返回2而不是1,因为£被编码有在UTF-8的两个字节。
"hello"
5
len(str)
len("£")
您可以RuneCountInString从 utf8 包中尝试。
RuneCountInString
返回 p 中的符文数
那个,如这个脚本所示:“世界”的长度可能是6(用中文写时:“世界”),但它的符文计数是2:
package main import "fmt" import "unicode/utf8" func main() { fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界")) }
Phrozen在评论中]补充道:
实际上,您可以len()通过类型转换来完成符文。 len([]rune("世界"))将打印2。至少在 Go 1.3 中。
len()
len([]rune("世界"))
2
并与CL 108985(五月2018年,为围棋1.11),len([]rune(string))现在已经进行了优化。(修复问题 24923)
len([]rune(string))
编译器len([]rune(string))自动检测模式,并将其替换为 for r := range s 调用。
添加一个新的运行时函数来计算字符串中的符文。修改编译器以检测模式len([]rune(string)) 并将其替换为新的符文计数运行时函数。 golang RuneCount/lenruneslice/ASCII 27.8ns ± 2% 14.5ns ± 3% -47.70% RuneCount/lenruneslice/Japanese 126ns ± 2% 60 ns ± 2% -52.03% RuneCount/lenruneslice/MixedLength 104ns ± 2% 50 ns ± 1% -51.71%
添加一个新的运行时函数来计算字符串中的符文。修改编译器以检测模式len([]rune(string)) 并将其替换为新的符文计数运行时函数。
golang RuneCount/lenruneslice/ASCII 27.8ns ± 2% 14.5ns ± 3% -47.70% RuneCount/lenruneslice/Japanese 126ns ± 2% 60 ns ± 2% -52.03% RuneCount/lenruneslice/MixedLength 104ns ± 2% 50 ns ± 1% -51.71%
什么是字符? 字符可以跨越多个符文。 例如,’ e‘ 和 ‘◌́◌́’(急性“\u0301”)可以组合形成 ‘é’(e\u0301NFD 中的“ ”)。这两个符文加在一起就是一个字符。 字符的定义可能因应用程序而异。 对于规范化,我们将其定义为: 以起始符开头的一系列符文, 不修改或与任何其他符文反向组合的符文, 后跟可能为空的非起始序列,即执行的符文(通常是重音符号)。 归一化算法一次处理一个字符。
字符可以跨越多个符文。 例如,’ e‘ 和 ‘◌́◌́’(急性“\u0301”)可以组合形成 ‘é’(e\u0301NFD 中的“ ”)。这两个符文加在一起就是一个字符。
e
e\u0301
字符的定义可能因应用程序而异。 对于规范化,我们将其定义为:
归一化算法一次处理一个字符。
使用该包及其Iter类型,“字符”的实际数量将是:
Iter
package main import "fmt" import "golang.org/x/text/unicode/norm" func main() { var ia norm.Iter ia.InitString(norm.NFKD, "école") nc := 0 for !ia.Done() { nc = nc + 1 ia.Next() } fmt.Printf("Number of chars: %d\n", nc) }
在这里,这使用了Unicode 规范化形式NFKD“兼容性分解”
指出,UNICODE 文本分割是可靠确定某些重要文本元素(用户感知的字符、单词和句子)之间默认边界的唯一方法。
为此,您需要一个像rivo/uniseg这样的外部库,它执行Unicode Text Segmentation。
将实际计数“字形簇”,其中多个码点可被组合成一个用户感知的字符。
package uniseg import ( "fmt" "github.com/rivo/uniseg" ) func main() { gr := uniseg.NewGraphemes("👍🏼!") for gr.Next() { fmt.Printf("%x ", gr.Runes()) } // Output: [1f44d 1f3fc] [21] }
两个字素,即使有三个符文(Unicode 代码点)。