Go言語はUnicodeテキストをネイティブにサポートしており、世界中のどの言語のテキストでも扱うことができます。これはstring型とrune型を通して実現されています。しかし、マルチバイト文字を扱う際にはいくつか注意点があります。
string型
- string型はイミュータブル(変更不可能)で、UTF-8でエンコードされた文字列を保持します。
- string内の文字は直接インデックスを使ってアクセスすることができますが、これはバイト単位でのアクセスであり、マルチバイト文字を構成する個々のバイトに分割される可能性があります。
- string型はテキストデータの読み込み、保存、伝送に適していますが、マルチバイト文字を一文字ずつ処理する場合には不便な場合があります。
rune型
- rune型は、Unicodeのコードポイントを表すためのint32型のエイリアスです。これは、Go言語において1文字(Unicodeスカラー値)を表します。
- rune型を使うと、UTF-8エンコードされたマルチバイト文字列を構成する各文字に対して、そのUnicodeコードポイントに基づいた操作を行うことができます。
- 文字列をruneスライスに変換することで、マルチバイト文字を含む文字列に対して文字単位で反復処理を行うことが容易になります。
string型とrune型の違い
- 表現の違い: string型はバイト列としてテキストデータを表現しますが、rune型はUnicodeコードポイントとして文字を表現します。
- 用途の違い: string型はテキストの格納や伝送に適しています。一方、rune型はテキストの文字単位での処理や解析に適しています。
- アクセス方法の違い: string型のインデックスアクセスはバイト単位ですが、rune型を使った処理では文字単位でのアクセスが可能です。
マルチバイト文字の反復処理
マルチバイト文字列を反復処理する際には、rangeループを使用すると便利です。rangeループは、string内の各rune値とそのインデックスを返します。これにより、UTF-8エンコードされた文字列内のマルチバイト文字を正しく扱うことができます。
package main
import "fmt"
func main() {
s := "こんにちは" // これはstring型
for i, r := range s { // `s`を`rune`として反復処理
fmt.Printf("%d: %q (%[2]U)\n", i, r)
}
}
出力
0: 'こ' (U+3053)
3: 'ん' (U+3093)
6: 'に' (U+306B)
9: 'ち' (U+3061)
12: 'は' (U+306F)
注意点:インデックス順位
- 〇 0, 3, 6, 9...
- ✖ 0, 1, 2, 3...
文字列とバイトスライスの変換
Go言語では、文字列をバイトスライスに変換することがよくあります。これは[]byte型を使用して行われます。しかし、マルチバイト文字が含まれる場合、単純なキャストでは文字が意図しない形で分割される可能性があります。正しく変換するには、文字列をruneスライスに変換し、それから必要に応じてバイト表現に変換することが推奨されます。
package main
import "fmt"
func main() {
s := "こんにちは"
runeSlice := []rune(s)
byteSlice := []byte(string(runeSlice))
for index, runeValue := range byteSlice {
fmt.Printf("%d\t%U\t%c\n", index, runeValue, runeValue)
}
}
出力
0 U+00E3 ã
1 U+0081
2 U+0093
3 U+00E3 ã
4 U+0082
5 U+0093
6 U+00E3 ã
7 U+0081
8 U+00AB «
9 U+00E3 ã
10 U+0081
11 U+00A1 ¡
12 U+00E3 ã
13 U+0081
14 U+00AF
Go言語でマルチバイト文字を扱う際には、stringとruneの違いを理解し、適切な方法で文字列を反復処理したり、バイトスライスに変換することが重要です。
オンラインデバッグ