...
1 package regexp2
2
3 import (
4 "bytes"
5 "errors"
6
7 "github.com/dlclark/regexp2/syntax"
8 )
9
10 const (
11 replaceSpecials = 4
12 replaceLeftPortion = -1
13 replaceRightPortion = -2
14 replaceLastGroup = -3
15 replaceWholeString = -4
16 )
17
18
19 type MatchEvaluator func(Match) string
20
21
22
23
24
25
26
27
28
29
30
31 func replace(regex *Regexp, data *syntax.ReplacerData, evaluator MatchEvaluator, input string, startAt, count int) (string, error) {
32 if count < -1 {
33 return "", errors.New("Count too small")
34 }
35 if count == 0 {
36 return "", nil
37 }
38
39 m, err := regex.FindStringMatchStartingAt(input, startAt)
40
41 if err != nil {
42 return "", err
43 }
44 if m == nil {
45 return input, nil
46 }
47
48 buf := &bytes.Buffer{}
49 text := m.text
50
51 if !regex.RightToLeft() {
52 prevat := 0
53 for m != nil {
54 if m.Index != prevat {
55 buf.WriteString(string(text[prevat:m.Index]))
56 }
57 prevat = m.Index + m.Length
58 if evaluator == nil {
59 replacementImpl(data, buf, m)
60 } else {
61 buf.WriteString(evaluator(*m))
62 }
63
64 count--
65 if count == 0 {
66 break
67 }
68 m, err = regex.FindNextMatch(m)
69 if err != nil {
70 return "", nil
71 }
72 }
73
74 if prevat < len(text) {
75 buf.WriteString(string(text[prevat:]))
76 }
77 } else {
78 prevat := len(text)
79 var al []string
80
81 for m != nil {
82 if m.Index+m.Length != prevat {
83 al = append(al, string(text[m.Index+m.Length:prevat]))
84 }
85 prevat = m.Index
86 if evaluator == nil {
87 replacementImplRTL(data, &al, m)
88 } else {
89 al = append(al, evaluator(*m))
90 }
91
92 count--
93 if count == 0 {
94 break
95 }
96 m, err = regex.FindNextMatch(m)
97 if err != nil {
98 return "", nil
99 }
100 }
101
102 if prevat > 0 {
103 buf.WriteString(string(text[:prevat]))
104 }
105
106 for i := len(al) - 1; i >= 0; i-- {
107 buf.WriteString(al[i])
108 }
109 }
110
111 return buf.String(), nil
112 }
113
114
115
116 func replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) {
117 for _, r := range data.Rules {
118
119 if r >= 0 {
120 buf.WriteString(data.Strings[r])
121 } else if r < -replaceSpecials {
122 m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
123 } else {
124 switch -replaceSpecials - 1 - r {
125 case replaceLeftPortion:
126 for i := 0; i < m.Index; i++ {
127 buf.WriteRune(m.text[i])
128 }
129 case replaceRightPortion:
130 for i := m.Index + m.Length; i < len(m.text); i++ {
131 buf.WriteRune(m.text[i])
132 }
133 case replaceLastGroup:
134 m.groupValueAppendToBuf(m.GroupCount()-1, buf)
135 case replaceWholeString:
136 for i := 0; i < len(m.text); i++ {
137 buf.WriteRune(m.text[i])
138 }
139 }
140 }
141 }
142 }
143
144 func replacementImplRTL(data *syntax.ReplacerData, al *[]string, m *Match) {
145 l := *al
146 buf := &bytes.Buffer{}
147
148 for _, r := range data.Rules {
149 buf.Reset()
150 if r >= 0 {
151 l = append(l, data.Strings[r])
152 } else if r < -replaceSpecials {
153 m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
154 l = append(l, buf.String())
155 } else {
156 switch -replaceSpecials - 1 - r {
157 case replaceLeftPortion:
158 for i := 0; i < m.Index; i++ {
159 buf.WriteRune(m.text[i])
160 }
161 case replaceRightPortion:
162 for i := m.Index + m.Length; i < len(m.text); i++ {
163 buf.WriteRune(m.text[i])
164 }
165 case replaceLastGroup:
166 m.groupValueAppendToBuf(m.GroupCount()-1, buf)
167 case replaceWholeString:
168 for i := 0; i < len(m.text); i++ {
169 buf.WriteRune(m.text[i])
170 }
171 }
172 l = append(l, buf.String())
173 }
174 }
175
176 *al = l
177 }
178
View as plain text