如何在 Go 中通过 runes 迭代字符串?

问题描述 投票:0回答:5

我想要这个:

for i := 0; i < len(str); i++ {
    dosomethingwithrune(str[i]) // takes a rune
}

但事实证明

str[i]
的类型为
byte
(
uint8
) 而不是
rune

如何通过符文而不是字节来迭代字符串?

string loops go rune
5个回答
181
投票

请参阅 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 代码点。


44
投票

为了反映 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 代码点的整数表示(请参阅围棋之旅)。


20
投票

例如:

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: 界

3
投票

或者,不使用

fmt
包的代码示例:

package main

func main() {
    for _, rune := range "Hello, 世界" {
        println(string(rune))
    }
}

在循环中,变量

r
表示当前正在迭代的
rune
。在将其打印到控制台之前,我们使用
string()
函数将其转换为字符串。

游乐场


0
投票

您可以查看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
}

字符串是从字节构建的,因此对它们进行索引会产生字节而不是字符,对于 acees 字符,您可以使用以下选项:

  1. 语言内置方式迭代符文:
for i, r := range "Hello, 世界" {
    fmt.Printf("%d\t%q\t%d\n", i, r, r)
}
  1. 通过从
    string
    获取符文数组:
runes := []rune("Hello, 世界")
for i := 0; i < len(runes) ; i++ {
    fmt.Printf("Rune : '%c'\n", runes[i])
}
  1. 通过使用标准库包utf8:
for i := 0; i < len(s); {
    r, size := utf8.DecodeRuneInString(s[i:])
    fmt.Printf("%d\t%c\n", i, r)
    i += size
}
© www.soinside.com 2019 - 2024. All rights reserved.