summaryrefslogtreecommitdiffstats
path: root/tpl/strings
diff options
context:
space:
mode:
authorCameron Moore <moorereason@gmail.com>2020-08-28 09:29:26 -0500
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2020-08-28 18:57:56 +0200
commitcdfd1c99baa22d69e865294dfcd783811f96c880 (patch)
tree0e2e21537de208baf493318c0e38b2b1631f7c8f /tpl/strings
parent047af7cfe5e9aa740b85e0f9974a2d31a0ef4c08 (diff)
tpl: Add limit support to replaceRE
Go stdlib doesn't contain a limited replace in the regexp package, but we can accomplish the same thing with ReplaceAllStringFunc. Fixes #7586
Diffstat (limited to 'tpl/strings')
-rw-r--r--tpl/strings/init.go11
-rw-r--r--tpl/strings/regexp.go22
-rw-r--r--tpl/strings/regexp_test.go30
3 files changed, 49 insertions, 14 deletions
diff --git a/tpl/strings/init.go b/tpl/strings/init.go
index 09419a51f..26d63519a 100644
--- a/tpl/strings/init.go
+++ b/tpl/strings/init.go
@@ -99,7 +99,16 @@ func init() {
ns.AddMethodMapping(ctx.ReplaceRE,
[]string{"replaceRE"},
- [][2]string{},
+ [][2]string{
+ {
+ `{{ replaceRE "a+b" "X" "aabbaabbab" }}`,
+ `XbXbX`,
+ },
+ {
+ `{{ replaceRE "a+b" "X" "aabbaabbab" 1 }}`,
+ `Xbaabbab`,
+ },
+ },
)
ns.AddMethodMapping(ctx.SliceString,
diff --git a/tpl/strings/regexp.go b/tpl/strings/regexp.go
index 7b52c9f6e..c6d731a0d 100644
--- a/tpl/strings/regexp.go
+++ b/tpl/strings/regexp.go
@@ -46,8 +46,9 @@ func (ns *Namespace) FindRE(expr string, content interface{}, limit ...interface
}
// ReplaceRE returns a copy of s, replacing all matches of the regular
-// expression pattern with the replacement text repl.
-func (ns *Namespace) ReplaceRE(pattern, repl, s interface{}) (_ string, err error) {
+// expression pattern with the replacement text repl. The number of replacements
+// can be limited with an optional fourth parameter.
+func (ns *Namespace) ReplaceRE(pattern, repl, s interface{}, n ...interface{}) (_ string, err error) {
sp, err := cast.ToStringE(pattern)
if err != nil {
return
@@ -63,12 +64,27 @@ func (ns *Namespace) ReplaceRE(pattern, repl, s interface{}) (_ string, err erro
return
}
+ nn := -1
+ if len(n) > 0 {
+ nn, err = cast.ToIntE(n[0])
+ if err != nil {
+ return
+ }
+ }
+
re, err := reCache.Get(sp)
if err != nil {
return "", err
}
- return re.ReplaceAllString(ss, sr), nil
+ return re.ReplaceAllStringFunc(ss, func(str string) string {
+ if nn == 0 {
+ return str
+ }
+
+ nn -= 1
+ return re.ReplaceAllString(str, sr)
+ }), nil
}
// regexpCache represents a cache of regexp objects protected by a mutex.
diff --git a/tpl/strings/regexp_test.go b/tpl/strings/regexp_test.go
index e05b00fb1..433181f67 100644
--- a/tpl/strings/regexp_test.go
+++ b/tpl/strings/regexp_test.go
@@ -46,7 +46,7 @@ func TestFindRE(t *testing.T) {
}
c.Assert(err, qt.IsNil)
- c.Assert(result, qt.DeepEquals, test.expect)
+ c.Check(result, qt.DeepEquals, test.expect)
}
}
@@ -58,19 +58,29 @@ func TestReplaceRE(t *testing.T) {
pattern interface{}
repl interface{}
s interface{}
+ n []interface{}
expect interface{}
}{
- {"^https?://([^/]+).*", "$1", "http://gohugo.io/docs", "gohugo.io"},
- {"^https?://([^/]+).*", "$2", "http://gohugo.io/docs", ""},
- {"(ab)", "AB", "aabbaab", "aABbaAB"},
+ {"^https?://([^/]+).*", "$1", "http://gohugo.io/docs", nil, "gohugo.io"},
+ {"^https?://([^/]+).*", "$2", "http://gohugo.io/docs", nil, ""},
+ {"(ab)", "AB", "aabbaab", nil, "aABbaAB"},
+ {"(ab)", "AB", "aabbaab", []interface{}{1}, "aABbaab"},
// errors
- {"(ab", "AB", "aabb", false}, // invalid re
- {tstNoStringer{}, "$2", "http://gohugo.io/docs", false},
- {"^https?://([^/]+).*", tstNoStringer{}, "http://gohugo.io/docs", false},
- {"^https?://([^/]+).*", "$2", tstNoStringer{}, false},
+ {"(ab", "AB", "aabb", nil, false}, // invalid re
+ {tstNoStringer{}, "$2", "http://gohugo.io/docs", nil, false},
+ {"^https?://([^/]+).*", tstNoStringer{}, "http://gohugo.io/docs", nil, false},
+ {"^https?://([^/]+).*", "$2", tstNoStringer{}, nil, false},
} {
- result, err := ns.ReplaceRE(test.pattern, test.repl, test.s)
+ var (
+ result string
+ err error
+ )
+ if len(test.n) > 0 {
+ result, err = ns.ReplaceRE(test.pattern, test.repl, test.s, test.n...)
+ } else {
+ result, err = ns.ReplaceRE(test.pattern, test.repl, test.s)
+ }
if b, ok := test.expect.(bool); ok && !b {
c.Assert(err, qt.Not(qt.IsNil))
@@ -78,6 +88,6 @@ func TestReplaceRE(t *testing.T) {
}
c.Assert(err, qt.IsNil)
- c.Assert(result, qt.Equals, test.expect)
+ c.Check(result, qt.Equals, test.expect)
}
}