UTF-8,Unicode, Goのbyte, rune関係がよく分からなかったのでいろいろ調べて、自分なりに解釈ができたので、まとめてみようと思います。
まずは定義から行きましょう。
UTF-8: Unicodeで使える8ビット符号単位の文字符号化形式
Unicode: 文字集合(文字セット)が単一の大規模文字セット
ようするに、UTF-8は、Unicodeを符号化(エンコード)するやつで、Unicodeはいろんな文字の集合です。
aとか"あ"とか"亜"とか、ほんといろいろな文字の集合。
そして、Unicodeの文字には、識別しやすいように数字が割り振られていて、その数字をコードポイント(Go言語でrune型に割り当てられる)といいます。実際にコードで違いを見てみましょう。
func main() { s := "あいうえお" b := []byte(s) for _, bi := range b { fmt.Printf("%x ", bi) //UTF-8でエンコードされた、16進数のバイト列 } fmt.Println() for _, ri := range s { fmt.Printf("%#U", ri) //コードポイント(rune) } }
実行結果
e3 81 82 e3 81 84 e3 81 86 e3 81 88 e3 81 8a U+3042 'あ'U+3044 'い'U+3046 'う'U+3048 'え'U+304A 'お'
"あいうえお"などのUnicodeを、UTF-8という変換器を使ってPC側が処理できるようにしたものがe3~~などのバイト列です。
UTF-8は可変長エンコーディングで、1~4バイトです。
各バイトの先頭は、ビットパターンが決まっています。
1バイト 0.......
2バイト 110..... 10......
3バイト 1110.... 10...... 10......
4バイト 111110... 10...... 10...... 10......
ASCIIと互換性を持たせるために、UTF-8の1バイトのみはASCIIになっています。
"あ"の16進数のバイト列は、e3 81 82です。
これを2進数に直すと、1110 0011 1000 0001 1000 0010 であり、各バイト先頭はきちんとビットパターン通りになっています。
このバイト列は、Goではbyte型として扱われます。
s := "あ" b := []byte(s) for _, bi := range b { fmt.Printf("%x ", bi) //e3 81 82 }
文字列をbyteスライスに変換して16進で取り出すと"e3 81 82"となり、byte型がUTF-8でエンコードされたバイト列だということが分かりました。
おまけ
func main() { s := "あいうえお" fmt.Printf("%v, %T\n", s[0:6], s[0:6]) //あい, string }
とやると、"あい"が出てきます。これは、スライスで取り出そうとすると、byteで取得してるからこうなってる訳ですね。それをデコードして、string型にしています。
参考記事
プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- 作者: Alan A.A. Donovan,Brian W. Kernighan,柴田芳樹
- 出版社/メーカー: 丸善出版
- 発売日: 2016/06/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る