Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

transform.Transformer使っていますか?

Slide 3

Slide 3 text

transform.Transformer とは

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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列を操作できる

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

transform.Transformer 実装の仕方

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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よりも小さいの が前提

Slide 14

Slide 14 text

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数

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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しないように調整が必要です

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

おまけ

Slide 22

Slide 22 text

私選!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

Slide 23

Slide 23 text

面白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

Slide 24

Slide 24 text

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