如何在Go中获取字符串的字符数?
例如,如果我有一个字符串"hello"
,该方法应该返回5
。我看到len(str)
返回字节数,而不是字符数,所以len("£")
返回2而不是1,因为in在UTF8中是用两个字节编码的。
发布于 2012-10-01 15:06:47
您可以尝试使用utf8包中的RuneCountInString
。
返回p中的符号数
这一点,如this script中所示:"World“的长度可能是6(当中文写成”世界“时),但它的符文计数是2:
package main
import "fmt"
import "unicode/utf8"
func main() {
fmt.Println("Hello, 世界", len("世界"), utf8.RuneCountInString("世界"))
}
实际上,您可以通过类型转换在符文上执行len()
。
len([]rune("世界"))
将打印2
。至少在Go 1.3中。
通过CL 108985 (2018年5月,针对Go 1.11),len([]rune(string))
现在得到了优化。(修复issue 24923)
编译器自动检测len([]rune(string))
模式,并将其替换为for r := range的调用。
添加了一个新的运行时函数来计算字符串中的符号数。修改编译器以检测模式
len([]rune(string))
,并将其替换为新的符文计数运行时函数。
RuneCount/lenruneslice/ASCII 27.8 ns±2%14.5 ns±3% -47.70%RuneCount/lenruneslice/日语126 ns±2%60 ns±2% -52.03%RuneCount/lenruneslice/MixedLength 104 ns±2% 50 ns±1% -51.71%
Stefan Steiger指向博客文章"Text normalization in Go“
什么是字符?正如在strings blog post中提到的,字符可以跨越多个符文。
例如,'e
‘和'◌́◌́’(急性的"\u0301")可以组合形成“é”(NFD中的“e\u0301
”)。这两个符文加在一起就是一个字符。
字符的定义可能因应用程序的不同而不同。
对于,我们将其定义为:
规范化算法一次处理一个字符。
使用该软件包及其Iter
type,实际“字符”数量将为:
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 Normalization form NFKD“兼容性分解”
Oliver的answer指出,是可靠地确定某些重要文本元素(用户感知的字符、单词和句子)之间默认边界的唯一方法。
为此,您需要一个像这样的外部库,它执行Unicode文本分割。
这实际上将计算" 集群“,其中多个代码点可以组合成一个用户感知的字符。
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代码点)。
您可以在"How to manipulate strings in GO to reverse them?“中看到其他示例。
本身是一个字素,但从unicode to code points converter中,有4个符文:
:
发布于 2016-04-04 00:54:08
有一种方法可以在没有任何包的情况下获得符文计数,方法是将字符串转换为[]符文作为len([]rune(YOUR_STRING))
package main
import "fmt"
func main() {
russian := "Спутник и погром"
english := "Sputnik & pogrom"
fmt.Println("count of bytes:",
len(russian),
len(english))
fmt.Println("count of runes:",
len([]rune(russian)),
len([]rune(english)))
}
字节的
计数30 16
符文计数16 16
发布于 2019-03-14 05:21:13
我应该指出的是,到目前为止,提供的答案都没有给出您期望的字符数,特别是当您处理表情符号时(但也有一些语言,如泰语、韩语或阿拉伯语)。VonC's suggestions将输出以下内容:
fmt.Println(utf8.RuneCountInString("️")) // Outputs "6".
fmt.Println(len([]rune("️"))) // Outputs "6".
这是因为这些方法只计算Unicode代码点。有许多字符,可以由多个码点组成。
var ia norm.Iter
ia.InitString(norm.NFKD, "️")
nc := 0
for !ia.Done() {
nc = nc + 1
ia.Next()
}
fmt.Println(nc) // Outputs "6".
归一化并不等同于计算字符,许多字符无法归一化为一个码点的等价物。
masakielastic's answer很接近,但只处理修饰符(彩虹标志包含一个修饰符,因此不会被算作它自己的代码点):
fmt.Println(GraphemeCountInString("️")) // Outputs "5".
fmt.Println(GraphemeCountInString2("️")) // Outputs "5".
在Unicode Standard Annex #29中定义了将Unicode字符串拆分成(用户可感知的)字符的正确方法,即字素簇。规则可以在Section 3.1.1中找到。github.com/rivo/uniseg包实现了这些规则,因此您可以确定字符串中的正确字符数:
fmt.Println(uniseg.GraphemeClusterCount("️")) // Outputs "2".
https://stackoverflow.com/questions/12668681
复制相似问题