-
Notifications
You must be signed in to change notification settings - Fork 291
/
space_table.go
105 lines (88 loc) · 2.56 KB
/
space_table.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
package formatx
import (
"bufio"
"strings"
"unicode"
"github.com/kubeshop/botkube/pkg/mathx"
)
// Table holds table data.
type Table struct {
Headers []string
Rows [][]string
}
// TableOutput returns table output.
type TableOutput struct {
Table Table
Lines []string
}
// TableSpace destructs table sparated by spaces.
type TableSpace struct{}
// TableSeparated takes a string input and returns a slice of slices containing the separated values in each row
// and a slice of the original input lines.
// TODO: change the output to a JSON or YAML format to allow standardized parser interface.
func (*TableSpace) TableSeparated(in string) TableOutput {
var out TableOutput
in = replaceTabsWithSpaces(in)
in = strings.TrimSpace(in)
scanner := bufio.NewScanner(strings.NewReader(in))
// Parse the headers
var separators []int
if scanner.Scan() {
line := scanner.Text()
separators = getSeparators(line)
out.Lines = append(out.Lines, line)
out.Table.Headers = splitIntoCells(line, separators)
}
// Parse the rows
for scanner.Scan() {
line := scanner.Text()
out.Lines = append(out.Lines, line)
row := splitIntoCells(line, separators)
out.Table.Rows = append(out.Table.Rows, row)
}
return out
}
func replaceTabsWithSpaces(in string) string {
return strings.ReplaceAll(in, "\t", " ")
}
// function takes a line and returns a list of separators (positions of left edges of the cells)
func getSeparators(line string) []int {
var separators []int
for idx, ch := range line {
isCurrentCharSpace := unicode.IsSpace(ch)
if !isCurrentCharSpace { // not separator
continue
}
var (
previousIdx = mathx.DecreaseWithMin(idx, 0)
nextIdx = mathx.IncreaseWithMax(idx, len(line)-1)
isNextSpace = unicode.IsSpace(rune(line[nextIdx]))
wasPrevSpace = unicode.IsSpace(rune(line[previousIdx]))
)
if isCurrentCharSpace && isNextSpace {
continue
}
if isCurrentCharSpace && !wasPrevSpace && !isNextSpace { // check for multi world colum name like "APP VERSION"
continue
}
separators = append(separators, idx)
}
return separators
}
// function takes a line and a list of separators and returns a list of cells (the line divided by the separators)
func splitIntoCells(line string, separators []int) []string {
var (
res []string
start = 0
)
separators = append(separators, len(line)) // to add the final "end", otherwise the last 'cell' won't be extracted
for _, end := range separators {
if end > len(line) {
end = len(line)
}
cell := strings.TrimSpace(line[start:end])
start = end
res = append(res, cell)
}
return res
}