-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathparser_aligned.go
More file actions
93 lines (88 loc) · 2.23 KB
/
parser_aligned.go
File metadata and controls
93 lines (88 loc) · 2.23 KB
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
package table
import (
"unicode/utf8"
)
// ParseAligned table. Tries to parse table which looks like this:
// a b c
// aa bb c
// a bbb c
//
// Please consult tests to see in which situations this function
// performs well and in which it does not.
// Number of columns in the table needs to be provided.
// If none of the rows has the expected number of column, error is returned.
// WARNING: This function does work only with ASCII strings
// (so result might be wrong for UTF-8 strings)
func ParseAligned(lines []string, nbColumn int) (Parsed, error) {
cols, err := columns(lines, nbColumn)
if err != nil {
return nil, err
}
result := make([]parsedLine, len(lines))
for i, line := range lines {
result[i] = parsedLine{
parsed: splitByCols(line, cols),
original: line}
}
return result, nil
}
func splitByCols(line string, cols []column) []string {
splitted := make([]string, len(cols))
for i, c := range cols {
if len(line) >= c.to {
from := findFrom(line, cols, i)
to := findTo(line, cols, i)
splitted[i] = line[from:to]
} else if len(line) > c.from {
from := findFrom(line, cols, i)
splitted[i] = line[from:]
} // if none of those two match splitted[i] will contains empty string
}
return splitted
}
func findFrom(line string, cols []column, i int) int {
prevColumn := 0
if i > 0 {
prevColumn = cols[i-1].to
}
from := cols[i].from
for {
_, w := utf8.DecodeLastRuneInString(line[:from])
// we can't extend return current
if w == 0 {
return from
}
// we have reached the line start
if from-w <= 0 {
return 0
}
// by extending the column we overlapped the previous column, lets return the original from
if from-w <= prevColumn {
return from
}
from -= w
}
}
func findTo(line string, cols []column, i int) int {
nextColumn := len(line)
if i < len(cols)-1 {
nextColumn = cols[i+1].from
}
to := cols[i].to
for {
_, w := utf8.DecodeRuneInString(line[to:])
// we can't extend return current
if w == 0 {
return to
}
// we have reached the line end, we are in the last column
if to+w == len(line) {
return len(line)
}
// by extending the column we overlapped the next column, lets return the original from
if to+w >= nextColumn {
return to
}
to += w
}
}