理系学生日記

おまえはいつまで学生気分なのか

hex-encodedな文字列をUTF-8に変換する

とあるプロジェクトの技術支援に入っているのですが、API リクエスト/レスポンスの送受信内容(UTF-8)のログが、すべてバイト列を hex-encoded されたものになっているようなシステムになっております。 人類は長い歴史を無為に生きてきたため、hex-encoded されたバイト列を頭の中で UTF-8 にエンコードできるほど進化しておりません。なんとかしないといけない。

そういうわけなので、なんとかして UTF-8 のバイト列が hex-encoded された文字列をプレインテキストに戻してやるツールが必要になります。 それでいて、開発は Windows でなされているので、ツールは Windows で動かないといけない。

おやおや、これは Go で書けば良いんじゃねーかと思いまして、初めて Go でプログラムを書いてみました。

こんなかんじで、hex-encoded された文字列を標準入力に食わせると、標準出力に結果を出力する。

$ cat hello
e38193e38293e381abe381a1e381af
e38193e38293e381abe381a1e381af
$ cat hello | ~/bin/hexstr
こんにちは
こんにちは

でも、自宅に Windows 環境ないし Windows で標準入力に投入するテストしにくかったのと、オプション解析を Go でどうやるのか試したかったので、オプション引数でファイル指定にも対応する実験をしてみた。

$ ~/bin/hexstr -i hello
こんにちは
こんにちは

Go の標準ライブラリが結構充実していたので、あんまし大した実装しなくて良い。 以下がだいたいの処理なんだけど、ファイル開いて hex-encoded の文字列を取り出して、それをデコードしてから utf-8 の文字列として出力するだけ。

func run(args []string) int {
    var scanner *bufio.Scanner
    var filename = flag.String("i", "", "file path which includes hex-encoded lines")

    flag.Parse()

    if *filename == "" {
        scanner = bufio.NewScanner(os.Stdin)
    } else {
        file, err := os.Open(*filename)
        if err != nil {
            fmt.Fprintf(os.Stderr, "file open error: %s\n", err)
            return ExitCodeOpenFileError
        }
        defer file.Close()

        scanner = bufio.NewScanner(file)
    }

    for scanner.Scan() {
        var hexString = scanner.Text()
        var decoded, err = hex.DecodeString(hexString)
        if err != nil {
            fmt.Fprintf(os.Stderr, "failed to decode \"%s\": %s\n", hexString, err)
            return ExitCodeInputError
        }
        fmt.Println(string(decoded))
    }

    if err := scanner.Err(); err != nil {
        fmt.Fprintf(os.Stderr, "scanner error: %s\n", err)
        return ExitCodeInputError
    }

    return ExitCodeOK
}

むしろつらかったのはツールチェーン系で、クロスコンパイルを楽にするための gox とか、いろいろあるのだなぁという学習コストそれなりにあったし、今後もありそう。まぁこのあたりの学習コストはどの言語でも必要なので、慣れるしかない。

l