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

标签 string for-loop go unicode utf-8

我正在阅读 Effective Go documentation 中有关 for 语句的部分并遇到了这个例子:

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 个字节,而“替换 rune ”(U+FFFD) 长 1 个字节,我接受并理解。但是,我认为 runeint32 类型,因此每个都是 4 个字节,而不是三个。

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

最佳答案

Go 中的

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

这里要注意一件事:并非所有可能的字节序列都是有效 UTF-8 序列。 string 可以是任何 字节序列,甚至是那些无效的 UTF-8 序列。例如,string"\xff" 表示无效的 UTF-8 字节序列,有关详细信息,请参见 How do I represent an Optional String in Go?

for range构造——当应用于 string 值时——迭代 string 的 rune :

For a string value, the "range" clause iterates over the Unicode code points in the string starting at byte index 0. On successive iterations, the index value will be the index of the first byte of successive UTF-8-encoded code points in the string, and the second value, of type rune, will be the value of the corresponding code point. If the iteration encounters an invalid UTF-8 sequence, the second value will be 0xFFFD, the Unicode replacement character, and the next iteration will advance a single byte in the string.

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

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

对于每次迭代,pos 将是 rune /字符的字节索引,而char 将是string 的 rune 。正如您在上面的引用中看到的,如果 string 是无效的 UTF-8 字节序列,当遇到无效的 UTF-8 序列时,char 将是 0xFFFD(Unicode 替换字符)和for range 构造(迭代)将前进一个仅单个字节

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

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

The Go Blog: Strings, bytes, runes and characters in Go

关于string - 在 UTF-8 字符串中循环时,是什么决定了字符的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41779147/

相关文章:

go - 所有 Go 函数都返回 err 作为第二个返回值吗?

java - 使用 Scanner 来分离字符串

java - 将文件转换为字节数组再转换为字符串的更有效方法

java - 为什么Java中以下列表无法转换为字符串数组

javascript - 使用 For Loop Javascript 动态创建变量

regex - golang选择性地将字符串转换为小写

c# - 判断一个句子是否包含特定的词

javascript - 如何通过 for 循环、mr[2] 和 test1[2] 添加 onclick

ios - 不能形成 Range with end < start

Golang 相当于 JavaScript 的参数?