1
0
Fork 0
mirror of https://github.com/gohugoio/hugo.git synced 2025-04-07 12:55:53 +00:00

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 
This commit is contained in:
Cameron Moore 2020-08-28 09:29:26 -05:00 committed by Bjørn Erik Pedersen
parent 047af7cfe5
commit cdfd1c99ba
3 changed files with 49 additions and 14 deletions

View file

@ -99,7 +99,16 @@ func init() {
ns.AddMethodMapping(ctx.ReplaceRE, ns.AddMethodMapping(ctx.ReplaceRE,
[]string{"replaceRE"}, []string{"replaceRE"},
[][2]string{}, [][2]string{
{
`{{ replaceRE "a+b" "X" "aabbaabbab" }}`,
`XbXbX`,
},
{
`{{ replaceRE "a+b" "X" "aabbaabbab" 1 }}`,
`Xbaabbab`,
},
},
) )
ns.AddMethodMapping(ctx.SliceString, ns.AddMethodMapping(ctx.SliceString,

View file

@ -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 // ReplaceRE returns a copy of s, replacing all matches of the regular
// expression pattern with the replacement text repl. // expression pattern with the replacement text repl. The number of replacements
func (ns *Namespace) ReplaceRE(pattern, repl, s interface{}) (_ string, err error) { // 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) sp, err := cast.ToStringE(pattern)
if err != nil { if err != nil {
return return
@ -63,12 +64,27 @@ func (ns *Namespace) ReplaceRE(pattern, repl, s interface{}) (_ string, err erro
return return
} }
nn := -1
if len(n) > 0 {
nn, err = cast.ToIntE(n[0])
if err != nil {
return
}
}
re, err := reCache.Get(sp) re, err := reCache.Get(sp)
if err != nil { if err != nil {
return "", err 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. // regexpCache represents a cache of regexp objects protected by a mutex.

View file

@ -46,7 +46,7 @@ func TestFindRE(t *testing.T) {
} }
c.Assert(err, qt.IsNil) 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{} pattern interface{}
repl interface{} repl interface{}
s interface{} s interface{}
n []interface{}
expect interface{} expect interface{}
}{ }{
{"^https?://([^/]+).*", "$1", "http://gohugo.io/docs", "gohugo.io"}, {"^https?://([^/]+).*", "$1", "http://gohugo.io/docs", nil, "gohugo.io"},
{"^https?://([^/]+).*", "$2", "http://gohugo.io/docs", ""}, {"^https?://([^/]+).*", "$2", "http://gohugo.io/docs", nil, ""},
{"(ab)", "AB", "aabbaab", "aABbaAB"}, {"(ab)", "AB", "aabbaab", nil, "aABbaAB"},
{"(ab)", "AB", "aabbaab", []interface{}{1}, "aABbaab"},
// errors // errors
{"(ab", "AB", "aabb", false}, // invalid re {"(ab", "AB", "aabb", nil, false}, // invalid re
{tstNoStringer{}, "$2", "http://gohugo.io/docs", false}, {tstNoStringer{}, "$2", "http://gohugo.io/docs", nil, false},
{"^https?://([^/]+).*", tstNoStringer{}, "http://gohugo.io/docs", false}, {"^https?://([^/]+).*", tstNoStringer{}, "http://gohugo.io/docs", nil, false},
{"^https?://([^/]+).*", "$2", tstNoStringer{}, 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 { if b, ok := test.expect.(bool); ok && !b {
c.Assert(err, qt.Not(qt.IsNil)) c.Assert(err, qt.Not(qt.IsNil))
@ -78,6 +88,6 @@ func TestReplaceRE(t *testing.T) {
} }
c.Assert(err, qt.IsNil) c.Assert(err, qt.IsNil)
c.Assert(result, qt.Equals, test.expect) c.Check(result, qt.Equals, test.expect)
} }
} }