mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05: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 #7586
This commit is contained in:
parent
047af7cfe5
commit
cdfd1c99ba
3 changed files with 49 additions and 14 deletions
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue