diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-01-17 09:35:16 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2023-01-17 12:14:11 +0100 |
commit | 2fb40ece5df38c3d6565cfd69ae194dbe0126f53 (patch) | |
tree | 2a0472335a48b0edf540c7495d6a8fabfe889271 | |
parent | c6b3887696162335d806ff25e9b9db27d73611de (diff) |
tpl/strings: Add findRESubmatch
Fixes #10594
-rw-r--r-- | tpl/internal/templatefuncsRegistry.go | 5 | ||||
-rw-r--r-- | tpl/strings/init.go | 12 | ||||
-rw-r--r-- | tpl/strings/regexp.go | 25 | ||||
-rw-r--r-- | tpl/strings/regexp_test.go | 33 |
4 files changed, 74 insertions, 1 deletions
diff --git a/tpl/internal/templatefuncsRegistry.go b/tpl/internal/templatefuncsRegistry.go index da9aa5d29..84e0e25fa 100644 --- a/tpl/internal/templatefuncsRegistry.go +++ b/tpl/internal/templatefuncsRegistry.go @@ -66,6 +66,11 @@ func (t *TemplateFuncsNamespace) AddMethodMapping(m any, aliases []string, examp name := methodToName(m) + // Rewrite §§ to ` in example commands. + for i, e := range examples { + examples[i][0] = strings.ReplaceAll(e[0], "§§", "`") + } + // sanity check for _, e := range examples { if e[0] == "" { diff --git a/tpl/strings/init.go b/tpl/strings/init.go index 0a4d87762..503ec6a25 100644 --- a/tpl/strings/init.go +++ b/tpl/strings/init.go @@ -78,12 +78,22 @@ func init() { []string{"findRE"}, [][2]string{ { - `{{ findRE "[G|g]o" "Hugo is a static side generator written in Go." "1" }}`, + `{{ findRE "[G|g]o" "Hugo is a static side generator written in Go." 1 }}`, `[go]`, }, }, ) + ns.AddMethodMapping(ctx.FindRESubmatch, + []string{"findRESubmatch"}, + [][2]string{ + { + `{{ findRESubmatch §§<a\s*href="(.+?)">(.+?)</a>§§ §§<li><a href="#foo">Foo</a></li> <li><a href="#bar">Bar</a></li>§§ | print | safeHTML }}`, + "[[<a href=\"#foo\">Foo</a> #foo Foo] [<a href=\"#bar\">Bar</a> #bar Bar]]", + }, + }, + ) + ns.AddMethodMapping(ctx.HasPrefix, []string{"hasPrefix"}, [][2]string{ diff --git a/tpl/strings/regexp.go b/tpl/strings/regexp.go index 5b6a812d4..84b015ffb 100644 --- a/tpl/strings/regexp.go +++ b/tpl/strings/regexp.go @@ -45,6 +45,31 @@ func (ns *Namespace) FindRE(expr string, content any, limit ...any) ([]string, e return re.FindAllString(conv, lim), nil } +// FindRESubmatch returns returns a slice of strings holding the text of the leftmost match of the regular expression in s and the matches, if any, of its subexpressions. +// +// By default all matches will be included. The number of matches can be limited with the optional limit parameter. A return value of nil indicates no match. +func (ns *Namespace) FindRESubmatch(expr string, content any, limit ...any) ([][]string, error) { + re, err := reCache.Get(expr) + if err != nil { + return nil, err + } + + conv, err := cast.ToStringE(content) + if err != nil { + return nil, err + } + n := -1 + if len(limit) > 0 { + n, err = cast.ToIntE(limit[0]) + if err != nil { + return nil, err + } + } + + return re.FindAllStringSubmatch(conv, n), nil + +} + // ReplaceRE returns a copy of s, replacing all matches of the regular // expression pattern with the replacement text repl. The number of replacements // can be limited with an optional fourth parameter. diff --git a/tpl/strings/regexp_test.go b/tpl/strings/regexp_test.go index 9ac098c17..b6ec5cb9e 100644 --- a/tpl/strings/regexp_test.go +++ b/tpl/strings/regexp_test.go @@ -50,6 +50,39 @@ func TestFindRE(t *testing.T) { } } +func TestFindRESubmatch(t *testing.T) { + t.Parallel() + c := qt.New(t) + + for _, test := range []struct { + expr string + content any + limit any + expect any + }{ + {`<a\s*href="(.+?)">(.+?)</a>`, `<li><a href="#foo">Foo</a></li><li><a href="#bar">Bar</a></li>`, -1, [][]string{ + {"<a href=\"#foo\">Foo</a>", "#foo", "Foo"}, + {"<a href=\"#bar\">Bar</a>", "#bar", "Bar"}, + }}, + // Some simple cases. + {"([G|g]o)", "Hugo is a static site generator written in Go.", -1, [][]string{{"go", "go"}, {"Go", "Go"}}}, + {"([G|g]o)", "Hugo is a static site generator written in Go.", 1, [][]string{{"go", "go"}}}, + + // errors + {"([G|go", "Hugo is a static site generator written in Go.", nil, false}, + {"([G|g]o)", t, nil, false}, + } { + result, err := ns.FindRESubmatch(test.expr, test.content, test.limit) + + if b, ok := test.expect.(bool); ok && !b { + c.Assert(err, qt.Not(qt.IsNil)) + continue + } + + c.Assert(err, qt.IsNil) + c.Check(result, qt.DeepEquals, test.expect) + } +} func TestReplaceRE(t *testing.T) { t.Parallel() c := qt.New(t) |