forked from ymotongpoo/goltsv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreader.go
85 lines (76 loc) · 1.88 KB
/
reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package goltsv
import (
"bufio"
"errors"
"io"
"strings"
)
// These are the errors that can be returned in ParseError.Error
var (
ErrFieldFormat = errors.New("wrong LTSV field format")
ErrLabelName = errors.New("unexpected label name")
)
// A Reader reads from a Labeled TSV (LTSV) file.
//
// As returned by NewReader, a Reader expects input conforming LTSV (http://ltsv.org/)
type LTSVReader struct {
reader *bufio.Reader
}
// NewReader returns a new LTSVReader that reads from r.
func NewReader(r io.Reader) *LTSVReader {
return <SVReader{bufio.NewReader(r)}
}
// error creates a new Error based on err.
// TODO(ymotongpoo): enhance parse error
func (r *LTSVReader) error(err error) error {
return err
}
// Read reads one record from r. The record is a map of string with
// each key and value representing one field.
func (r *LTSVReader) Read() (record map[string]string, err error) {
var line []byte
record = make(map[string]string)
for {
line, _, err = r.reader.ReadLine()
if err != nil {
return nil, err
}
sline := strings.TrimSpace(string(line))
if sline == "" {
// Skip empty line
continue
}
tokens := strings.Split(sline, "\t")
if len(tokens) == 0 {
return nil, r.error(ErrFieldFormat)
}
for _, field := range tokens {
if field == "" {
continue
}
data := strings.SplitN(field, ":", 2)
if len(data) != 2 {
return record, r.error(ErrLabelName)
}
record[data[0]] = data[1]
}
return record, nil
}
return
}
// ReadAll reads all the remainig records from r.
// Each records is a slice of map of fields.
// TODO(ymotongpoo): compare with the case of using csv.ReadAll()
func (r *LTSVReader) ReadAll() (records []map[string]string, err error) {
for {
record, err := r.Read()
if err == io.EOF {
return records, nil
}
if err != nil {
return nil, err
}
records = append(records, record)
}
panic("unreachable")
}