Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UTF-8 依存の Go コードとは?

acomagu
June 29, 2019

UTF-8 依存の Go コードとは?

BigLT 2019

acomagu

June 29, 2019
Tweet

More Decks by acomagu

Other Decks in Technology

Transcript

  1. UTF-8依存のGoコードとは
    190629 Aizu BigLT
    @acomagu

    View Slide

  2. 今日のゴール
    - Goの標準の文字コードとは何か?
    - UTF-8依存のコードとは?
    - 正しくUTF-8を処理する方法を知る
    → ドキュメントと実装に差異がないようにしよう

    View Slide

  3. Go標準の文字コードとは?

    View Slide

  4. s に入れるべき文字コードはわかりますか?
    (ここにある情報のみで)

    View Slide

  5. godoc.org/builtin

    View Slide

  6. godoc.org/builtin

    View Slide

  7. 特定の文字コードにしか対応しないなら
    ドキュメントに書かなければならない!

    View Slide

  8. View Slide

  9. View Slide

  10. でも...
    UTF-8依存のコードなんて
    書いた覚えないけど?

    View Slide

  11. UTF-8依存のコードとは?

    View Slide

  12. UTF-8依存クイズ~!!

    View Slide

  13. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    }

    View Slide

  14. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return string(bts)
    }
    []byte -> string

    View Slide

  15. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return string(bts)
    }
    []byte -> string 非依存

    View Slide

  16. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return string(rns)
    }
    []rune -> string

    View Slide

  17. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return string(rns)
    }
    []rune -> string 依存

    View Slide

  18. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []byte(str)
    }
    string -> []byte

    View Slide

  19. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []byte(str)
    }
    string -> []byte 非依存

    View Slide

  20. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []byte(rns)
    }
    []rune -> []byte

    View Slide

  21. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []byte(rns)
    }
    []rune -> []byte 依存

    View Slide

  22. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []rune(str)
    }
    string -> []rune

    View Slide

  23. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []rune(str)
    }
    string -> []rune 依存

    View Slide

  24. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []rune(bts)
    }
    []byte -> []rune

    View Slide

  25. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return []rune(bts)
    }
    []byte -> []rune 依存

    View Slide

  26. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return len(str)
    }

    View Slide

  27. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    return len(str)
    }
    非依存

    View Slide

  28. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    for i := 0; i < len(str); i++ {
    _ = str[i]
    }
    }

    View Slide

  29. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    for i := 0; i < len(str); i++ {
    _ = str[i]
    }
    } 非依存

    View Slide

  30. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    for i := range str {
    _ = str[i]
    }
    }

    View Slide

  31. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    for i := range str {
    _ = str[i]
    }
    } 依存

    View Slide

  32. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    bytes.Index([]byte(str1), []byte(str2))
    }

    View Slide

  33. UTF-8依存? 非依存?
    func cast(str string, bts []byte, rns []rune) {
    bytes.Index([]byte(str1), []byte(str2))
    }
    依存

    View Slide

  34. お疲れ様です
    (ありがとうございます)

    View Slide

  35. まとめ
    - rune が絡むキャストはUTF-8依存
    - string を range にかけるとUTF-8依存
    - しかし len(str) や str[i] は非依存

    View Slide

  36. bytes.Index 問について...
    Shift-JISだと
    “表” “\”
    0x95 0x5C 0x5C

    View Slide

  37. bytes.Index 問について...
    Shift-JISだと
    “表” “\”
    0x95 0x5C 0x5C
    bytes.Index にかけるとまずい...

    View Slide

  38. bytes.Index 問について...
    1バイト目 2バイト目以降

    View Slide

  39. bytes.Index 問について...
    1バイト目 2バイト目以降
    違う → bytes.Index大丈夫

    View Slide

  40. 正しくUTF-8を処理するには

    View Slide

  41. ① ASCII 依存にしない
    例えば: UTF-8 で ”Number” はたくさんある
    → Unicode のキャラクタクラスを適切に利用する
    → コメントに ASCII Number のみと記載する

    View Slide

  42. ② 正規化/比較で正しい手順を踏む
    - 例えば:
    - Unicode の正規化と比較方法は RFC8264(PRECIS) として
    定義されている
    - 「いつ使うべきか」も記述がある
    - golang.org/x/text/secure/precis

    View Slide

  43. ③ Grapheme Cluster を意識する
    Grapheme Cluster とは? → 「1文字の境界」を定義する仕様

    View Slide

  44. ③ Grapheme Cluster を意識する
    Grapheme Cluster とは? → 「1文字の境界」を定義する仕様
    「1文字 == 1コードポイント」じゃないの?
    → Variation Selector が付与されている場合がある

    View Slide

  45. ③ Grapheme Cluster を意識する
    絵文字とか良くね?

    View Slide

  46. ③ Grapheme Cluster を意識する
    Go では大変...
    - 標準ライブラリにはない
    - 外部ライブラリを使用
    - Proposal は出てる
    - 正規表現での対応は不可能そう
    - \X ...

    View Slide

  47. まとめ
    - Go の型には UTF-8 依存のものはないが、キャストなどには
    いくつかある
    - ASCII 依存 / PRECIS / Grepheme Cluster を意識する
    → どこまで対応しているのかドキュメントでしっかり明確にしよ

    View Slide

  48. Thanks!

    View Slide