循环 UTF-8 字符串时,是什么决定了字符的位置?

2024-01-12

我正在阅读有关的部分for中的陈述有效的 Go 文档 https://golang.org/doc/effective_go.html并遇到了这个例子:

for pos, char := range "日本\x80語" {
    fmt.Printf("Character %#U, at position: %d\n", char, pos)
}

输出是:

Character U+65E5 '日', at position: 0
Character U+672C '本', at position: 3
Character U+FFFD '�', at position: 6
Character U+8A9E '語', at position: 7

我不明白的是为什么位置是 0、3、6 和 7。这告诉我第一个和第二个字符是 3 个字节长,“替换符文”(U+FFFD) 是 1 个字节长,我接受并理解。然而,我想rune was of int32类型,因此每个字节为 4 个字节,而不是 3 个字节。

为什么范围内的位置与每个值应消耗的内存总量不同?


stringGo 中的值存储为只读字节片([]byte),其中字节是 ( 的 UTF-8 编码字节rune的)string. UTF-8 https://en.wikipedia.org/wiki/UTF-8是一种可变长度编码,不同的 Unicode 代码点可以使用不同数量的字节进行编码。例如范围内的值0..127被编码为单个字节(其值是 unicode 代码点本身),但大于 127 的值使用超过 1 个字节。这unicode/utf8 https://golang.org/pkg/unicode/utf8/包中包含UTF-8相关的实用函数和常量,例如utf8.UTFMax报告有效 Unicode 代码点在 UTF-8 编码中可以“占用”的最大字节数(为 4)。

这里需要注意一件事:not所有可能的字节序列是validUTF-8 序列。 Astring may be any字节序列,甚至是无效的 UTF-8 序列。例如string value "\xff"表示无效的UTF-8字节序列,详情参见如何在 Go 中表示可选字符串? https://stackoverflow.com/questions/30731687/how-do-i-represent-an-optional-string-in-go/30741287#30741287

The for range https://golang.org/ref/spec#For_statements构造——当应用于stringvalue——迭代的符文string:

对于字符串值,“range”子句从字节索引 0 开始迭代字符串中的 Unicode 代码点。在连续迭代中,索引值将是连续 UTF-8 编码代码点的第一个字节的索引字符串和类型的第二个值rune,将是相应代码点的值。如果迭代遇到无效的 UTF-8 序列,则第二个值将为0xFFFD,Unicode 替换字符,下一次迭代将在字符串中前进一个字节。

The for range构造可能会产生 1 或 2 个迭代值。当使用 2 时,如您的示例所示:

for pos, char := range "日本\x80語" {
    fmt.Printf("Character %#U, at position: %d\n", char, pos)
}

对于每次迭代,pos将是符文/字符的字节索引,并且char将是符文string。正如您在上面的引用中看到的,如果string是无效的UTF-8字节序列,当遇到无效的UTF-8序列时,char0xFFFD(Unicode 替换字符),以及for range构造(迭代)将推进仅单字节.

把它们加起来:位置始终是字节索引rune当前迭代的(或更具体地说:UTF-8 编码序列的第一个字节的字节索引rune当前迭代的位置),但如果遇到无效的UTF-8序列,则在下一次迭代中位置(索引)只会增加1。

如果您想了解有关该主题的更多信息,必读博客文章:

Go 博客:Go 中的字符串、字节、符文和字符 https://blog.golang.org/strings

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

循环 UTF-8 字符串时,是什么决定了字符的位置? 的相关文章

随机推荐