一尘不染

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

go

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

例如,如果我有一个字符串,"hello"该方法应该返回5. 我看到len(str)返回的字节数,而不是字符的数量,以便len("£")返回2而不是1,因为£被编码有在UTF-8的两个字节。


阅读 173

收藏
2021-11-05

共1个答案

一尘不染

您可以RuneCountInString从 utf8 包中尝试。

返回 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 中。


并与CL 108985(五月2018年,为围棋1.11),len([]rune(string))现在已经进行了优化。(修复问题 24923

编译器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%


什么是字符?

字符可以跨越多个符文
例如,’ e‘ 和 ‘◌́◌́’(急性“\u0301”)可以组合形成 ‘é’(e\u0301NFD 中的“ ”)。这两个符文加在一起就是一个字符

字符的定义可能因应用程序而异。
对于规范化,我们将其定义为:

  • 以起始符开头的一系列符文,
  • 不修改或与任何其他符文反向组合的符文,
  • 后跟可能为空的非起始序列,即执行的符文(通常是重音符号)。

归一化算法一次处理一个字符。

使用该包及其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 代码点)。

2021-11-05