3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Goで固定長データを取り扱った話

Last updated at Posted at 2014-06-24

自分がメンテナンスしている昔からあるperlスクリプトがデータの料が増えて処理にかなり時間がかかって体感的に遅いと感じるようになってきた。

そのスクリプトは標準ライブラリ程度にしか依存していなかったのでGoで書きなおしてみようかと思ってやってみた。

扱うデータのヘッダー部分が16進数の固定長データでperlではunpackして解析していた。 Goでunpackってどうやるの?ってなってその時の対応の備忘録。

Perlのpack/unpackについてはこの記事を参照。
perlpacktut - pack と unpack のチュートリアル - perldoc.jp

    while (<>) { 
        my($date, $desc, $income, $expend) = unpack("A10xA27xA7A*", $_);
        ...
    }

Goで16進数の固定長データをどう扱ったかというと基本は strconv.ParseUintと hex.DecodeStringだけで問題なかった。

先頭からN byteまとめて10進数に変換するならこう。

    s := "ABCDEF"
    ui, _ := strconv.ParseUint(s[:2], 16, 0)
    fmt.Printf("%#V\n", ui)  // %!V(uint64=2748)

逆に、2byteずつ変換するならこんな感じ。

    s := "ABCDEF"
    bytea, _ := hex.DecodeString(s[0:6])
    fmt.Printf("%#V\n", bytea)  // %!V([]uint8=[171 205 239])

これで16進数の固定長のデータが大体変換できるだろう。
strconv.ParseUint の第2引数で8進数でも2進数でも変換は可能となる万能な関数。
個人的に16進数で日付データとか持たせていてそれをデコードして出来たuint8のbyte配列に対してmapで文字列に変換したいと思ったんだけどいい実装が無かったので泥臭くPrintfで処理した。
mapのような関数型なプログラミングが恋しい。

package main

import "fmt"
import "strconv"
import "encoding/hex"

func main() {
    s := "ABCDEF"

    // Nbyteまとめて変換するならこう
    bytea, _ := hex.DecodeString(s[0:6])
    fmt.Printf("%#V\n", bytea)

    // 先頭から2byteずつ変換するならこう
    ui, _ := strconv.ParseUint(s[:2], 16, 0)
    fmt.Printf("%#V\n", ui)

}

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?