Skip to content
Harald Weidner edited this page Jan 29, 2021 · 2 revisions

Unicode, UTF-8, Strings und Byte Slices

String-Literale und UTF-8

Go-Quelltexte sind per Definition in UTF-8, einer weit verbreiteten Kodierung des Unicode Zeichenvorrats. Damit sind auch String-Literale, wie sie in Quelltexten vorkommen, UTF-8.

text := "aö世界."

In diesem Beispiel ist der String text 10 Bytes lang: ein ASCII-Zeichen (ein Byte), ein Umlaut (zwei Bytes), zwei Kanji (je drei Bytes) und am Ende wieder ein ASCII-Zeichen.

fmt.Println(len(text)) // ergibt 10

Intern wird ein String als ein (unveränderlicher) Slice von Bytes repräsentiert. Der Variablentyp string wird jedoch, anders als beispielsweise []byte, als UTF-8 behandelt, was sich z.B. beim range Operator zeigt:

for i, c := range text {
	fmt.Printf("%d -> %c\n", i, c)
}

ergibt:

0 -> a
1 -> ö
3 -> 世
6 -> 界
9 -> .

Der range Operator iteriert also über die Unicode Codepunkte des UTF-8 Strings und gibt jeweils die Byte-Position des Zeichens (als Variable vom Typ int) und das Zeichen als Unicode (Typ rune bzw. int32) zurück.

Unicode-Codepunkte

Wenn man lieber direkt mit Unicode arbeiten möchte, bietet Go die Möglichkeit, einen String von UTF-8 nach Unicode zu konvertieren:

utext := []rune(text)
fmt.Println(len(utext))
for i, c := range utext {
	fmt.Printf("%d -> %c\n", i, c)
}

ergibt die Ausgabe:

5
0 -> a
1 -> ö
2 -> 世
3 -> 界
4 -> .

In Unicode ist der Text also nur noch fünf Zeichen lang, und der range Operator iteriert über die die fünf Elemente des []rune Slice. Als Unicode belegt der Text allerdings intern 20 Bytes (fünf Codepunkte zu je vier Bytes), während der String in UTF-8 nur zehn Bytes lang ist. Die Konvertierung von string nach []rune erfordert intern immer ein Umkopieren der Daten.

Byte Slices

Ebenso lässt sich ein String in seine Byte-Repräsentation umwandeln:

bytes := []byte(text)
fmt.Println(len(bytes))
for i, c := range bytes {
	fmt.Printf("%d -> %d\n", i, c)
}

ergibt:

10
0 -> 97
1 -> 195
2 -> 182
3 -> 228
4 -> 184
5 -> 150
6 -> 231
7 -> 149
8 -> 140
9 -> 46

Der Slice ist also, wie der String, 10 Zeichen lang. Der range Operator iteriert aber über jedes einzelne Zeichen; diese sind u.U. nicht-druckbare Zeichen, daher werden sie in diesem Beispiel als Dezimalzahl ausgegeben.

Weitere Informationen