/
response.go
108 lines (91 loc) · 2.68 KB
/
response.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
package requester
import (
"regexp"
)
type Response struct {
Body string
}
// Apply the regular expression and return the list of all sub-matches
// and a list of the positions. The positions are unique, and calculated
// doing an average of the positions of all sub-matches.
func (r *Response) ReList(re *regexp.Regexp) ([][]string, []int) {
matchs := re.FindAllStringSubmatch(r.Body, -1)
pos := re.FindAllStringSubmatchIndex(r.Body, -1)
// Merge positions into a single value (the start one)
newpos := make([]int, len(pos))
for i, p := range pos {
sum := 0
items := 0
for _, n := range p {
sum += n
items++
}
newpos[i] = sum / items
}
return matchs, newpos
}
func (r *Response) Re(re *regexp.Regexp) ([]string, []int) {
m, p := r.ReList(re)
if m != nil {
return m[0], p
}
return nil, nil
}
// ==================================================================
type Result struct {
Re *regexp.Regexp
Len int
}
type ResultList struct {
matchs [][][]string
cur int
}
func (l *ResultList) Next() bool {
l.cur++
return l.cur < len(l.matchs[0])
}
func (l *ResultList) Re(i int) []string {
if i < 0 || i >= len(l.matchs) {
panic("wrong re position")
}
return l.matchs[i][l.cur]
}
// Merge lists of matches and positions for a search.
// The first result passed will be the base one, the reference for the
// max length and the starting point of each section.
// Then each one of the rest will be checked and assigned to one of that
// sections according to it's starting position too.
// The result it's an iterator you can use to access all the joined data
// at once (it will return empty strings lists for the non-existent matchs).
func (r *Response) MergeResults(results []*Result) (*ResultList, error) {
// Take the base positions
baseMatchs, basePos := r.ReList(results[0].Re)
AssertLen(baseMatchs, results[0].Len)
matchs := make([][][]string, len(results))
matchs[0] = baseMatchs
// Calculate the offsets for each of the other ones
for i, _ := range results {
if i == 0 {
continue
}
// Obtain the derivated list of items
ms, ps := r.ReList(results[i].Re)
AssertLen(ms, results[i].Len)
if len(ms) > len(baseMatchs) {
return nil, Errorf("more results for derivated list than in the base one")
}
matchs[i] = make([][]string, len(baseMatchs))
cur := 0
for j, _ := range matchs[i] {
// If the next section it's still valid, skip this one with an empty
// list; otherwise fill it with the matched contents
if cur >= len(ps) || (j < len(basePos)-1 && basePos[j+1] < ps[cur]) {
matchs[i][j] = make([]string, results[i].Len)
} else {
matchs[i][j] = ms[cur]
cur++
}
}
}
return &ResultList{matchs: matchs, cur: -1}, nil
}