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

golang.org/x/text/transformを用いた文字列変換のススメ

tom twinkle
December 09, 2022

 golang.org/x/text/transformを用いた文字列変換のススメ

golang.org/x/text/transformを使ったcustom transformの作成の仕方

tom twinkle

December 09, 2022
Tweet

Other Decks in Programming

Transcript

  1. golang.org/x/text/transformを用いた文
    字列変換のススメ
    ANDPAD inc.
    tomoki.harada (tomtwinkle)
    Let’s transform!

    View full-size slide

  2. transform.Transformer使っていますか?

    View full-size slide

  3. transform.Transformer
    とは

    View full-size slide

  4. https://pkg.go.dev/golang.org/x/text
    @v0.4.0/transform

    View full-size slide

  5. something output
    something output
    io.Writer
    io.Reader
    Transformer
    Transformer
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=110
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=209
    transform.Writer
    transform.Reader
    something input
    something input
    “abc”
    [\x97,\x98,\x99]
    “adc”
    [\x97,\x100,\x99]
    “b” -> “d”
    \x98 -> \x100
    全てのbyte列をメモリに載せなくても Streamのまま部分的にbyte列を操作できる

    View full-size slide

  6. ● メモリ使用量を抑える
    ● memory allocation, GCによる速度
    低下を避ける

    View full-size slide

  7. それっぽいキーワードで探してもあまり見つからない

    View full-size slide

  8. transform.Transformer
    実装の仕方

    View full-size slide

  9. https://cs.opensource.google/go/x/text/+/internal-branch.g
    o1.19-vendor:transform/transform.go;l=41
    byte列の変換処理
    Transformer再利用の為のリセットメソッド
    (Transformer内部state変数の値リセット)

    View full-size slide

  10. https://cs.opensource.google/go/x/text/+/internal-branch.g
    o1.19-vendor:transform/transform.go;l=104
    Transformer内部でstateを持たない場合はResetの実装が不要なので
    NopResetterをstructにEmbedded

    View full-size slide

  11. https://cs.opensource.google/go/x/text/+/internal-branch.g
    o1.19-vendor:transform/transform.go;l=41

    View full-size slide

  12. something output
    something output
    io.Writer
    Buffer
    Transform()
    Transform()
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=110
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=209
    transform.Writer transform.Reader
    something input
    something input
    Buffer
    io.Reader
    srcのbyte列
    もっと欲しい
    → ErrShortSrc
    dstのbuffer
    size足りてない
    → ErrShortDst

    View full-size slide

  13. Transformの戻り値のerrorについて
    Error Type 説明
    transform.ErrShortDst
    srcの入力に対してdst bufferが不足している際に返却する
    Transformerはdst bufferをioに一旦書き込み、またdst
    bufferを空にしてTransformを呼び出す
    これを返さないと4096byte以上処理できない
    transform.ErrShortSrc
    Streamでやってきたsrcの入力情報だけでは不足していて処
    理出来ず次のsrcも読み込む必要がある場合に返却する
    (Hello->Hiに変換する処理でHellしかinputにない等)
    当然、ErrShortDstとかち合うのでdst bufferよりも小さいの
    が前提

    View full-size slide

  14. something output
    something output
    io.Writer
    Buffer
    Transform()
    Transform()
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=110
    https://cs.opensource.google/go/x/text/+/refs/tags/v0.4.0:transform/transform.go;l=209
    transform.Writer transform.Reader
    something input
    something input
    Buffer
    io.Reader
    nDst=dstに格
    納したbyte数
    nSrc=srcから
    dstにcopyした
    byte数

    View full-size slide

  15. https://go.dev/play/p/ezCskczrmlf
    何も変換しないNop Transformer

    View full-size slide

  16. https://go.dev/play/p/T7G8n-kNrNW
    何も変換しないNop Transformer

    View full-size slide

  17. https://github.com/tomtwinkle/garbledreplacer
    UTF-8からShift-JISに変換する際に出来ない文字を置き換えるTransformer

    View full-size slide

  18. 準パッケージのTransformerは変換出来ないとerrorになってしまう

    View full-size slide

  19. https://github.com/tomtwinkle/garbledreplacer
    UTF-8からShift-JISに変換する際に出来ない文字を置き換えるTransformer
    transformに渡されるbyte列が文字列であるとは限ら
    ないため文字列かどうかの判定を行う
    srcが最後のbyte列の場合はatEOF=trueになる
    このロジック上では無くても動作上問題ないが、余計な処理が走らないよう
    にearly returnしている
    runeがShift-JISでencode出来るかチェック
    encode出来なかったら別の文字に置き換え
    変換後のbyte列がdstのbufferからあふれる場合は dstに
    copyせずにErrShortDstを返して次の処理に回す
    nDstの値を適切に返していれば次回の処理では未処理の
    byte列を繋げて返してくれます ←!!
    マルチバイト文字注意ポイント
    マルチバイト文字の途中で srcが途切れた場合は
    そのbyte列をdstにcopyしないように調整が必要です

    View full-size slide

  20. 今まで作成したTransformer
    ● UTF-8をShift-JISに変換し、変換できない文字を置き換
    える
    https://github.com/tomtwinkle/garbledreplacer
    ● UTF-8 BOMを削除する
    https://github.com/tomtwinkle/utfbomremover
    ● 特定の文字列を別の文字列に変換
    https://github.com/tomtwinkle/gostrreplacer

    View full-size slide

  21. 私選!Githubで公開されている面白Transformer
    ● 特定の文字列を別の文字列に変換
    https://github.com/tenntenn/text
    ℳ → M
    ● Windows向けのCodePage Decoder
    https://github.com/mattn/go-localereader
    CP932(Shift-JIS), CP1200(UTF-16), CP65001(UTF-8)
    ● ニーモニックEncoder/Decoder(パスワード等の乱数のような意味のな
    い英数字を理解しやすい単語に変換して電話越しで伝えやすくする)
    https://github.com/schollz/mnemonicode
    こんな感じの変換
    8f9240688685a1e9 ↔ magic-slang-crimson--inch-calypso-ibiza

    View full-size slide

  22. 面白Transformer番外編
    ● uber-go/configシェルライクなシークエンス(${hoge}みたいな記述)
    を展開する実装
    https://github.com/uber-go/config/blob/v1.4.0/expand.go#L124
    ● andybalholm/redwood tgulacsi/go文字列内で重複するスペースを削
    除する実装
    https://github.com/andybalholm/redwood/blob/v1.7.0/word.go#L53
    https://github.com/tgulacsi/go/blob/v0.24.0/stream/trim.go#L39
    ● BurntSushi/graphics-go 画像をアフィン変換する実装
    https://github.com/BurntSushi/graphics-go/blob/master/graphics/affine.go#L61

    View full-size slide

  23. マルチバイト文字を扱うアジア圏の我々
    だからこそTransformerを賢く扱ってい
    きましょう!
    (もっと情報が増えて欲しい…!)

    View full-size slide