如何在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("世界")) }
实际上len(),只需键入强制转换即可完成符文。 len([]rune("世界"))将打印2。在Go 1.3中。
len()
len([]rune("世界"))
2
借助CL 108985(2018年5月,适用于Go 1.11),len([]rune(string))现已进行了优化。(修复了问题24923)
len([]rune(string))
编译器len([]rune(string))自动检测模式,并将其替换为r:= range调用。
添加一个新的运行时函数以计算字符串中的符文。修改编译器以检测模式,len([]rune(string)) 并将其替换为新的符文计数运行时函数。
RuneCount/lenruneslice/ASCII 27.8ns ± 2% 14.5ns ± 3% -47.70% (p=0.000 n=10+10) RuneCount/lenruneslice/Japanese 126ns ± 2% 60ns ± 2% -52.03% (p=0.000 n=10+10) RuneCount/lenruneslice/MixedLength 104ns ± 2% 50ns ± 1% -51.71% (p=0.000 n=10+9)
Stefan Steiger指向博客文章“ Go中的文本规范化 ”
什么是角色?
正如字符串博客文章中提到的那样, 角色可以跨越多个符文 。 例如,一个’ e‘和’◌́◌́’(急性“ \ u0301”)可以组合成一个’é’(e\u0301在NFD中为“ ”)。 这两个符文合在一起是一个角色 。 字符的定义可能会因应用程序而异。 为了 规范化, 我们将其定义为: 以起动器开始的一系列符文, 不会修改或向后组合任何其他符文的符文, 随后可能是空的非启动器序列,即具有此功能的符文(通常为重音符号)。 归一化算法一次处理一个字符。
正如字符串博客文章中提到的那样, 角色可以跨越多个符文 。 例如,一个’ e‘和’◌́◌́’(急性“ \ u0301”)可以组合成一个’é’(e\u0301在NFD中为“ ”)。 这两个符文合在一起是一个角色 。
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“兼容性分解”
Oliver的答案指出 UNICODE TEXT SEGMENTATION 是可靠确定某些重要文本元素(用户感知的字符,单词和句子)之间默认边界的唯一方法。
为此,您需要一个像 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代码点),也有两个字素。