YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

LTSVのGo用のreader/writerを書いた

はじめに

こんにちは、Go界の加東大介です。今週にわかにLTSVというビッグウェーブが訪れましたね。

乗っかるべくGo用のreader/writerを書きました。ビックウェーブに乗っかったエントリということで。自分としては今回のポイントはGoでLTSV用のライブラリを書いたことよりも、テストをdrone.ioでやってることだと思います。

goltsv

最初はよく仕様を読まないで書き始めてencoding/csvを使ってreaderだけ殴り書きしたら、mattnさんに誤りの指摘を頂いたのと修正パッチをpull request頂いたのでmergeしました。mattnさん、どうもありがとうございます!その後、writerも追加しました。 概ね、encoding/csvと同様の実装となっています。

サンプル

reader

readerは読み込んだLTSVをmap[string]stringの形にします。

package main

import (
    "bytes"
    "fmt"
    goltsv "github.com/ymotongpoo/goltsv"
)
   
func main() {
    // データ
    data := `
egg:たまご ham:ハム  bread:パン
gyoza:ぎょうざ    ramen:ラーメン  sushi:すし    yakiniku:焼肉
yamanashi:山梨  tokyo:東京    okinawa:沖縄  hokkaido:北海道
`
    b := bytes.NewBufferString(data)
   
    // Read LTSV data into map[string]string
    reader := goltsv.NewReader(b)
    records, err := reader.ReadAll()
    if err != nil {
        panic(err)
    }
   
    // dump
    for i, record := range records {
        fmt.Printf("===== Data %d\n", i)
        for k, v := range record {
            fmt.Printf("\t%s --> %s\n", k, v)
        }
    }
}

こんなかんじでデータがとれますね

% go run reader_example.go
===== Data 0
    bread --> パン
    egg --> たまご
    ham --> ハム
===== Data 1
    ramen --> ラーメン
    gyoza --> ぎょうざ
    sushi --> すし
    yakiniku --> 焼肉
===== Data 2
    yamanashi --> 山梨
    tokyo --> 東京
    hokkaido --> 北海道
    okinawa --> 沖縄

writer

writerのほうはmap[string]stringをLTSV形式にして吐き出します。

package main

import (
    "fmt"
    "bytes"
    goltsv "github.com/ymotongpoo/goltsv"
)

func main() {
    data := []map[string]string {
        {"Python": "3.3.0", "Ruby": "2.0 rc2", "Perl": "5.16.2"},
        {"spam": "foo", "egg": "bar", "ham": "buz"},
        {"sauce": "ソース", "salt": "しお", "sugar": "さとう", "vinegar": "す"},
    }

    b := &bytes.Buffer{}
    writer := goltsv.NewWriter(b)
    err := writer.WriteAll(data)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v", b.String())
}

こんなかんじでデータを書き出せます。

% go run writer_example.go 
Ruby:2.0 rc2   Python:3.3.0  Perl:5.16.2
ham:buz egg:bar spam:foo
vinegar:す sugar:さとう sauce:ソース salt:しお

今後

LTSVの仕様で特に触れてはいませんが、Goのmapの仕様だと、ラベルが増えた場合にwriterから吐き出すとフィールドの順序が変わる可能性があって、そのへんは気にした方がいいのかどうかというのが微妙なところです。 とりあえずGitHubに公開しているので、Pull Requestが来てから考えればいいか、と思ってとりあえずこのまま。