[][]string
へのDecodeで我慢できるのであれば、encoding/csv パッケージがそれなりに使える。
- ファイル終端にいくとEOFする
- 引用符ありなしを自動解釈
- 引用符中のダブルクォート2つ重ねを1つにしてくれる
- 引用符中なら改行文字を何いれてもいい
- \はエスケープ文字としてみなさない
Decode
package textdata import ( "encoding/csv" "fmt" "io" "time" ) func DecodeCSV(r io.Reader) ([]Textdata, error) { rc := csv.NewReader(r) datas := make([]Textdata, 0) i := 0 for { row, err := rc.Read() i = i + 1 if err != nil { if err == io.EOF { break } return nil, err } if len(row) < 2 { return nil, fmt.Errorf("invalid row. too less columns num. [position]: row %d [data]: %s", i, row) } data := Textdata{} data.Caption = row[0] data.Body = row[1] datas = append(datas, data) } return datas, nil }
test
package textdata import ( "strings" "testing" ) // Search is a function search textdata in shared repository func TestDecodeCSV(t *testing.T) { gotest := func(csv string, expect []Textdata) { r := strings.NewReader(csv) datas, err := DecodeCSV(r) if err != nil { msg := "error occured" t.Error(msg) } if len(expect) != len(datas) { t.Errorf("expect %d records, but returns %d.\r\n[expect]:%s\r\n[result]:%s", len(expect), len(datas), expect, datas) return } } genExpect := func(caption string, body string) Textdata { return Textdata{Caption: caption, Body: body, CreateAt: ""} } gotest(`a,b`, []Textdata{genExpect("a", "b")}) gotest(`"a",b`, []Textdata{genExpect("a", "b")}) gotest(`a,"b"`, []Textdata{genExpect("a", "b")}) gotest(`"""a""","b"`, []Textdata{genExpect("\"a\"", "b")}) gotest(`"""a\r\nb\rc\nd""","b"`, []Textdata{genExpect("\"a\r\nb\rc\nd\"", "b")}) }