/
matchRanges.go
73 lines (57 loc) · 1.61 KB
/
matchRanges.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
package m
import "regexp"
// MatchRanges collects match indices
type MatchRanges struct {
Matches [][2]int
}
// getMatchRanges locates one or more regexp matches in a string
func getMatchRanges(String *string, Pattern *regexp.Regexp) *MatchRanges {
if Pattern == nil {
return nil
}
return &MatchRanges{
Matches: toRunePositions(Pattern.FindAllStringIndex(*String, -1), String),
}
}
// Convert byte indices to rune indices
func toRunePositions(byteIndices [][]int, matchedString *string) [][2]int {
var returnMe [][2]int
if len(byteIndices) == 0 {
// Nothing to see here, move along
return returnMe
}
runeIndex := 0
byteIndicesToRuneIndices := make(map[int]int, 0)
for byteIndex := range *matchedString {
byteIndicesToRuneIndices[byteIndex] = runeIndex
runeIndex++
}
// If a match touches the end of the string, that will be encoded as one
// byte past the end of the string. Therefore we must add a mapping for
// first-index-after-the-end.
byteIndicesToRuneIndices[len(*matchedString)] = runeIndex
for _, bytePair := range byteIndices {
fromRuneIndex := byteIndicesToRuneIndices[bytePair[0]]
toRuneIndex := byteIndicesToRuneIndices[bytePair[1]]
returnMe = append(returnMe, [2]int{fromRuneIndex, toRuneIndex})
}
return returnMe
}
// InRange says true if the index is part of a regexp match
func (mr *MatchRanges) InRange(index int) bool {
if mr == nil {
return false
}
for _, match := range mr.Matches {
matchFirstIndex := match[0]
matchLastIndex := match[1] - 1
if index < matchFirstIndex {
continue
}
if index > matchLastIndex {
continue
}
return true
}
return false
}