Mercurial > yakumo_izuru > aya
comparison vendor/github.com/dlclark/regexp2/replace.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author | yakumo.izuru |
---|---|
date | Sun, 23 Jul 2023 13:18:53 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
65:6d985efa0f7a | 66:787b5ee0289d |
---|---|
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 // MatchEvaluator is a function that takes a match and returns a replacement string to be used | |
19 type MatchEvaluator func(Match) string | |
20 | |
21 // Three very similar algorithms appear below: replace (pattern), | |
22 // replace (evaluator), and split. | |
23 | |
24 // Replace Replaces all occurrences of the regex in the string with the | |
25 // replacement pattern. | |
26 // | |
27 // Note that the special case of no matches is handled on its own: | |
28 // with no matches, the input string is returned unchanged. | |
29 // The right-to-left case is split out because StringBuilder | |
30 // doesn't handle right-to-left string building directly very well. | |
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 // Given a Match, emits into the StringBuilder the evaluated | |
115 // substitution pattern. | |
116 func replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) { | |
117 for _, r := range data.Rules { | |
118 | |
119 if r >= 0 { // string lookup | |
120 buf.WriteString(data.Strings[r]) | |
121 } else if r < -replaceSpecials { // group lookup | |
122 m.groupValueAppendToBuf(-replaceSpecials-1-r, buf) | |
123 } else { | |
124 switch -replaceSpecials - 1 - r { // special insertion patterns | |
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 { // string lookup | |
151 l = append(l, data.Strings[r]) | |
152 } else if r < -replaceSpecials { // group lookup | |
153 m.groupValueAppendToBuf(-replaceSpecials-1-r, buf) | |
154 l = append(l, buf.String()) | |
155 } else { | |
156 switch -replaceSpecials - 1 - r { // special insertion patterns | |
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 } |