summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/dlclark/regexp2/replace.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/dlclark/regexp2/replace.go')
-rw-r--r--vendor/github.com/dlclark/regexp2/replace.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/vendor/github.com/dlclark/regexp2/replace.go b/vendor/github.com/dlclark/regexp2/replace.go
new file mode 100644
index 0000000000..0376bd9d37
--- /dev/null
+++ b/vendor/github.com/dlclark/regexp2/replace.go
@@ -0,0 +1,177 @@
+package regexp2
+
+import (
+ "bytes"
+ "errors"
+
+ "github.com/dlclark/regexp2/syntax"
+)
+
+const (
+ replaceSpecials = 4
+ replaceLeftPortion = -1
+ replaceRightPortion = -2
+ replaceLastGroup = -3
+ replaceWholeString = -4
+)
+
+// MatchEvaluator is a function that takes a match and returns a replacement string to be used
+type MatchEvaluator func(Match) string
+
+// Three very similar algorithms appear below: replace (pattern),
+// replace (evaluator), and split.
+
+// Replace Replaces all occurrences of the regex in the string with the
+// replacement pattern.
+//
+// Note that the special case of no matches is handled on its own:
+// with no matches, the input string is returned unchanged.
+// The right-to-left case is split out because StringBuilder
+// doesn't handle right-to-left string building directly very well.
+func replace(regex *Regexp, data *syntax.ReplacerData, evaluator MatchEvaluator, input string, startAt, count int) (string, error) {
+ if count < -1 {
+ return "", errors.New("Count too small")
+ }
+ if count == 0 {
+ return "", nil
+ }
+
+ m, err := regex.FindStringMatchStartingAt(input, startAt)
+
+ if err != nil {
+ return "", err
+ }
+ if m == nil {
+ return input, nil
+ }
+
+ buf := &bytes.Buffer{}
+ text := m.text
+
+ if !regex.RightToLeft() {
+ prevat := 0
+ for m != nil {
+ if m.Index != prevat {
+ buf.WriteString(string(text[prevat:m.Index]))
+ }
+ prevat = m.Index + m.Length
+ if evaluator == nil {
+ replacementImpl(data, buf, m)
+ } else {
+ buf.WriteString(evaluator(*m))
+ }
+
+ count--
+ if count == 0 {
+ break
+ }
+ m, err = regex.FindNextMatch(m)
+ if err != nil {
+ return "", nil
+ }
+ }
+
+ if prevat < len(text) {
+ buf.WriteString(string(text[prevat:]))
+ }
+ } else {
+ prevat := len(text)
+ var al []string
+
+ for m != nil {
+ if m.Index+m.Length != prevat {
+ al = append(al, string(text[m.Index+m.Length:prevat]))
+ }
+ prevat = m.Index
+ if evaluator == nil {
+ replacementImplRTL(data, &al, m)
+ } else {
+ al = append(al, evaluator(*m))
+ }
+
+ count--
+ if count == 0 {
+ break
+ }
+ m, err = regex.FindNextMatch(m)
+ if err != nil {
+ return "", nil
+ }
+ }
+
+ if prevat > 0 {
+ buf.WriteString(string(text[:prevat]))
+ }
+
+ for i := len(al) - 1; i >= 0; i-- {
+ buf.WriteString(al[i])
+ }
+ }
+
+ return buf.String(), nil
+}
+
+// Given a Match, emits into the StringBuilder the evaluated
+// substitution pattern.
+func replacementImpl(data *syntax.ReplacerData, buf *bytes.Buffer, m *Match) {
+ for _, r := range data.Rules {
+
+ if r >= 0 { // string lookup
+ buf.WriteString(data.Strings[r])
+ } else if r < -replaceSpecials { // group lookup
+ m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
+ } else {
+ switch -replaceSpecials - 1 - r { // special insertion patterns
+ case replaceLeftPortion:
+ for i := 0; i < m.Index; i++ {
+ buf.WriteRune(m.text[i])
+ }
+ case replaceRightPortion:
+ for i := m.Index + m.Length; i < len(m.text); i++ {
+ buf.WriteRune(m.text[i])
+ }
+ case replaceLastGroup:
+ m.groupValueAppendToBuf(m.GroupCount()-1, buf)
+ case replaceWholeString:
+ for i := 0; i < len(m.text); i++ {
+ buf.WriteRune(m.text[i])
+ }
+ }
+ }
+ }
+}
+
+func replacementImplRTL(data *syntax.ReplacerData, al *[]string, m *Match) {
+ l := *al
+ buf := &bytes.Buffer{}
+
+ for _, r := range data.Rules {
+ buf.Reset()
+ if r >= 0 { // string lookup
+ l = append(l, data.Strings[r])
+ } else if r < -replaceSpecials { // group lookup
+ m.groupValueAppendToBuf(-replaceSpecials-1-r, buf)
+ l = append(l, buf.String())
+ } else {
+ switch -replaceSpecials - 1 - r { // special insertion patterns
+ case replaceLeftPortion:
+ for i := 0; i < m.Index; i++ {
+ buf.WriteRune(m.text[i])
+ }
+ case replaceRightPortion:
+ for i := m.Index + m.Length; i < len(m.text); i++ {
+ buf.WriteRune(m.text[i])
+ }
+ case replaceLastGroup:
+ m.groupValueAppendToBuf(m.GroupCount()-1, buf)
+ case replaceWholeString:
+ for i := 0; i < len(m.text); i++ {
+ buf.WriteRune(m.text[i])
+ }
+ }
+ l = append(l, buf.String())
+ }
+ }
+
+ *al = l
+}