BigLT 2019
UTF-8依存のGoコードとは190629 Aizu BigLT@acomagu
View Slide
今日のゴール- Goの標準の文字コードとは何か?- UTF-8依存のコードとは?- 正しくUTF-8を処理する方法を知る→ ドキュメントと実装に差異がないようにしよう
Go標準の文字コードとは?
s に入れるべき文字コードはわかりますか?(ここにある情報のみで)
godoc.org/builtin
特定の文字コードにしか対応しないならドキュメントに書かなければならない!
でも...UTF-8依存のコードなんて書いた覚えないけど?
UTF-8依存のコードとは?
UTF-8依存クイズ~!!
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {}
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return string(bts)}[]byte -> string
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return string(bts)}[]byte -> string 非依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return string(rns)}[]rune -> string
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return string(rns)}[]rune -> string 依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []byte(str)}string -> []byte
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []byte(str)}string -> []byte 非依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []byte(rns)}[]rune -> []byte
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []byte(rns)}[]rune -> []byte 依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []rune(str)}string -> []rune
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []rune(str)}string -> []rune 依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []rune(bts)}[]byte -> []rune
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return []rune(bts)}[]byte -> []rune 依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return len(str)}
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {return len(str)}非依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {for i := 0; i < len(str); i++ {_ = str[i]}}
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {for i := 0; i < len(str); i++ {_ = str[i]}} 非依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {for i := range str {_ = str[i]}}
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {for i := range str {_ = str[i]}} 依存
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {bytes.Index([]byte(str1), []byte(str2))}
UTF-8依存? 非依存?func cast(str string, bts []byte, rns []rune) {bytes.Index([]byte(str1), []byte(str2))}依存
お疲れ様です(ありがとうございます)
まとめ- rune が絡むキャストはUTF-8依存- string を range にかけるとUTF-8依存- しかし len(str) や str[i] は非依存
bytes.Index 問について...Shift-JISだと“表” “\”0x95 0x5C 0x5C
bytes.Index 問について...Shift-JISだと“表” “\”0x95 0x5C 0x5Cbytes.Index にかけるとまずい...
bytes.Index 問について...1バイト目 2バイト目以降
bytes.Index 問について...1バイト目 2バイト目以降違う → bytes.Index大丈夫
正しくUTF-8を処理するには
① ASCII 依存にしない例えば: UTF-8 で ”Number” はたくさんある→ Unicode のキャラクタクラスを適切に利用する→ コメントに ASCII Number のみと記載する
② 正規化/比較で正しい手順を踏む- 例えば:- Unicode の正規化と比較方法は RFC8264(PRECIS) として定義されている- 「いつ使うべきか」も記述がある- golang.org/x/text/secure/precis
③ Grapheme Cluster を意識するGrapheme Cluster とは? → 「1文字の境界」を定義する仕様
③ Grapheme Cluster を意識するGrapheme Cluster とは? → 「1文字の境界」を定義する仕様「1文字 == 1コードポイント」じゃないの?→ Variation Selector が付与されている場合がある
③ Grapheme Cluster を意識する絵文字とか良くね?
③ Grapheme Cluster を意識するGo では大変...- 標準ライブラリにはない- 外部ライブラリを使用- Proposal は出てる- 正規表現での対応は不可能そう- \X ...
まとめ- Go の型には UTF-8 依存のものはないが、キャストなどにはいくつかある- ASCII 依存 / PRECIS / Grepheme Cluster を意識する→ どこまで対応しているのかドキュメントでしっかり明確にしよう
Thanks!