首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何获取字符串中的字符数

如何获取字符串中的字符数
EN

Stack Overflow用户
提问于 2012-10-01 14:52:15
回答 7查看 112.5K关注 0票数 170

如何在Go中获取字符串的字符数?

例如,如果我有一个字符串"hello",该方法应该返回5。我看到len(str)返回字节数,而不是字符数,所以len("£")返回2而不是1,因为in在UTF8中是用两个字节编码的。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 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("世界"))
}

Phrozen增加了in the comments

实际上,您可以通过类型转换在符文上执行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“兼容性分解”

Oliveranswer指出,是可靠地确定某些重要文本元素(用户感知的字符、单词和句子)之间默认边界的唯一方法。

为此,您需要一个像这样的外部库,它执行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个符文:

women (1f469)

票数 206
EN

Stack Overflow用户

发布于 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

票数 48
EN

Stack Overflow用户

发布于 2019-03-14 05:21:13

我应该指出的是,到目前为止,提供的答案都没有给出您期望的字符数,特别是当您处理表情符号时(但也有一些语言,如泰语、韩语或阿拉伯语)。VonC's suggestions将输出以下内容:

fmt.Println(utf8.RuneCountInString("️‍")) // Outputs "6".
fmt.Println(len([]rune("️‍"))) // Outputs "6".

这是因为这些方法只计算Unicode代码点。有许多字符,可以由多个码点组成。

与使用Normalization package相同

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".
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12668681

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档