diff options
author | Cameron Moore <moorereason@gmail.com> | 2020-08-28 09:29:26 -0500 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-08-28 18:57:56 +0200 |
commit | cdfd1c99baa22d69e865294dfcd783811f96c880 (patch) | |
tree | 0e2e21537de208baf493318c0e38b2b1631f7c8f /tpl/strings | |
parent | 047af7cfe5e9aa740b85e0f9974a2d31a0ef4c08 (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.go | 11 | ||||
-rw-r--r-- | tpl/strings/regexp.go | 22 | ||||
-rw-r--r-- | tpl/strings/regexp_test.go | 30 |
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) } } |