Как я могу перебрать строку по рунам в Go?
Я хотел это:
for i := 0; i < len(str); i++ {
dosomethingwithrune(str[i]) // takes a rune
}
Но оказывается, что str[i]
имеет тип byte
(uint8
) скорее, чем rune
,
Как я могу перебрать строку по рунам, а не по байтам?
4 ответа
Посмотрите этот пример из 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
Для строк диапазон делает больше для вас, разбивая отдельные кодовые точки Unicode путем анализа UTF-8.
Чтобы отразить пример, приведенный на 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 (см. A Tour of Go).
Например:
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()
перед печатью на консоли.