我想要这个:
for i := 0; i < len(str); i++ {
dosomethingwithrune(str[i]) // takes a rune
}
但事实证明
str[i]
的类型为 byte
(uint8
) 而不是 rune
。
如何通过符文而不是字节来迭代字符串?
请参阅 Effective Go 中的示例:
for pos, char := range "日本語" {
fmt.Printf("character %c starts at byte position %d\n", char, pos)
}
此打印:
character 日 starts at byte position 0
character 本 starts at byte position 3
character 語 starts at byte position 6
对于字符串,该范围可以为您做更多的工作,打破个人 通过解析 UTF-8 得到 Unicode 代码点。
为了反映 golang.org 给出的示例,Go 允许您轻松地将字符串转换为符文切片,然后对其进行迭代,就像您最初想要的那样:
runes := []rune("Hello, 世界")
for i := 0; i < len(runes) ; i++ {
fmt.Printf("Rune %v is '%c'\n", i, runes[i])
}
当然,我们也可以像这里的其他示例一样使用范围运算符,但这更符合您的原始语法。无论如何,这将输出:
Rune 0 is 'H'
Rune 1 is 'e'
Rune 2 is 'l'
Rune 3 is 'l'
Rune 4 is 'o'
Rune 5 is ','
Rune 6 is ' '
Rune 7 is '世'
Rune 8 is '界'
请注意,由于
rune
类型是 int32
的别名,因此我们必须在 %c
语句中使用 %v
而不是通常的 Printf
,否则我们将看到 Unicode 代码点的整数表示(请参阅围棋之旅)。
例如:
package main
import "fmt"
func main() {
for i, rune := range "Hello, 世界" {
fmt.Printf("%d: %c\n", i, rune)
}
}
输出:
0: H
1: e
2: l
3: l
4: o
5: ,
6:
7: 世
10: 界
或者,不使用
fmt
包的代码示例:
package main
func main() {
for _, rune := range "Hello, 世界" {
println(string(rune))
}
}
在循环中,变量
r
表示当前正在迭代的rune
。在将其打印到控制台之前,我们使用 string()
函数将其转换为字符串。
您可以查看doc。
rune
基本上是 int32
类型的别名:
type rune = int32
Go 中的文字字符串以 UTF-8 格式进行编码,这基本上允许存储与 unicode table:
中的字符相对应的 unicode 代码0xxxxxxx unicode codes 0−127
110xxxxx 10xxxxxx 128−2047
1110xxxx 10xxxxxx 10xxxxxx 2048−65535
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536−0x10ffff
正如您所看到的,这样的编码每个字符需要 1-4 个字节,这就是为什么我们在这里有
rune = int32
(4 字节)来适应最坏的情况,当我们需要 4 字节来编码 unicode 字符代码时。
从 Unicode table 您可以看到,如果您的
string
仅包含拉丁字母字符和数字(ASCII 字符),那么 string
中的符文数量将等于字节数,因为这样的 ASCII 字符需要只需要编码 1 个字节。但当您使用非 ASCII 字符时,情况就不是这样了:
import "unicode/utf8"
func countRunes() {
s := "Hello, 世界"
fmt.Println(len(s)) // "13" - bytes
fmt.Println(utf8.RuneCountInString(s)) // "9" - runes characters
}
for i, r := range "Hello, 世界" {
fmt.Printf("%d\t%q\t%d\n", i, r, r)
}
string
获取符文数组:runes := []rune("Hello, 世界")
for i := 0; i < len(runes) ; i++ {
fmt.Printf("Rune : '%c'\n", runes[i])
}
for i := 0; i < len(s); {
r, size := utf8.DecodeRuneInString(s[i:])
fmt.Printf("%d\t%c\n", i, r)
i += size
}