-
Notifications
You must be signed in to change notification settings - Fork 1
/
header.go
130 lines (112 loc) · 2.58 KB
/
header.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package csvd
import (
"strings"
"unicode"
"unicode/utf8"
)
// CanonicalHeaderKey returns the canonical format of the header key.
// For example, the canonical key for " User\t Id " is "user id".
func CanonicalHeaderKey(key string) string {
var hasSpace bool
var start, size int
var r rune
var b strings.Builder
for start < len(key) {
r, size = utf8.DecodeRuneInString(key[start:])
if !unicode.IsSpace(r) {
break
}
start += size
}
key = key[start:]
start = 0
if start < len(key) {
for {
if unicode.IsUpper(r) {
goto canonicalHeaderKey
}
if unicode.IsSpace(r) {
if hasSpace || r != ' ' {
goto canonicalHeaderKey
}
hasSpace = true
} else {
hasSpace = false
}
start += size
if start < len(key) {
r, size = utf8.DecodeRuneInString(key[start:])
} else {
break
}
}
}
if hasSpace {
return key[:start-size]
}
return key
canonicalHeaderKey:
b.Grow(len(key))
b.WriteString(key[:start])
for {
if unicode.IsSpace(r) {
hasSpace = true
} else {
if hasSpace {
b.WriteByte(' ')
}
b.WriteRune(unicode.ToLower(r))
hasSpace = false
}
start += size
if start < len(key) {
r, size = utf8.DecodeRuneInString(key[start:])
} else {
break
}
}
return b.String()
}
// ParseHeader parses a csv file header.
func ParseHeader(record []string) Header {
h := make(Header, len(record))
for i, key := range record {
h.Set(key, i)
}
return h
}
// Header represents the key-index pairs in the csv file header.
// The keys should be in canonical form, as returned by CanonicalHeaderKey.
type Header map[string]int
// Set sets the header entries associated with key to the single index.
// It replaces any existing values associated with key.
//
// The key is canonicalized by CanonicalHeaderKey.
func (h Header) Set(key string, index int) {
h[CanonicalHeaderKey(key)] = index
}
// Get gets the index associated with the given key.
// If there are no index associated with the key, Get returns -1.
//
// The key is canonicalized by CanonicalHeaderKey.
func (h Header) Get(key string) int {
idx, ok := h[CanonicalHeaderKey(key)]
if !ok {
return -1
}
return idx
}
// Get checks if has a index associated with the given key.
// If there are no index associated with the key, Get returns -1.
//
// The key is canonicalized by CanonicalHeaderKey.
func (h Header) Has(key string) bool {
_, ok := h[CanonicalHeaderKey(key)]
return ok
}
// Del deletes the index associated with the given key.
//
// The key is canonicalized by CanonicalHeaderKey.
func (h Header) Del(key string) {
delete(h, CanonicalHeaderKey(key))
}