-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathparser_csv.go
106 lines (96 loc) · 2.2 KB
/
parser_csv.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package table
import (
"encoding/csv"
"io"
"reflect"
"strings"
"time"
"github.com/pkg/errors"
)
// CSV type provides functionality to search and parse CSV structure
type CSV struct {
Reader *csv.Reader
}
// FindField reads the CSV content until finding matching cell.
func (r CSV) FindField(matcher FieldMatcher) (string, bool, error) {
var out, ok = "", false
var err error
for {
var row []string
row, err = r.Reader.Read()
if err != nil {
break
}
out, ok = matcher(row)
if ok {
break
}
}
if err != nil && err != io.EOF {
return out, false, errors.Wrap(err, "can't find field")
}
return out, ok, nil
}
// ForeachLine finds table (starting with header and ending with whitespace row)
// and forwards each row to f
func (r CSV) ForeachLine(header []string, f func([]string)) error {
time.Now().AddDate(0, 1, 2)
var err error
var matchedHeader bool
for row := []string{}; err == nil; row, err = r.Reader.Read() {
if !matchedHeader {
matchedHeader = isHeader(header, row)
continue
} else if stringsOnlyWhitespace(row) {
return nil
}
f(row)
}
if err != io.EOF {
return errors.Wrap(err, "can't read csv")
}
if matchedHeader {
return nil
}
return errors.Errorf("can't find header, expected: %q", header)
}
// line must be `header` followed by whitespace fields
func isHeader(header, line []string) bool {
if len(line) < len(header) {
return false
}
return reflect.DeepEqual(header, trimSpace(line[:len(header)])) &&
stringsOnlyWhitespace(line[len(header):])
}
// trimSpace trims spaces in the given slice
// similar to strings.TrimSpace for a slice
func trimSpace(ls []string) []string {
for i := range ls {
ls[i] = strings.TrimSpace(ls[i])
}
return ls
}
// stringsOnlyWhitespace checks if input consists of only whitespace
func stringsOnlyWhitespace(s []string) bool {
for _, elem := range s {
if strings.TrimSpace(elem) != "" {
return false
}
}
return true
}
// FromStrStrSlice Parsed is created
func FromStrStrSlice(lines [][]string, comma ...string) Parsed {
var sep = "\t"
if len(comma) > 0 {
sep = comma[0]
}
p := Parsed{}
for _, l := range lines {
p = append(p, parsedLine{
parsed: l,
original: strings.Join(l, sep),
})
}
return p
}