Skip to content

Commit

Permalink
tpl/strings: Add findRESubmatch
Browse files Browse the repository at this point in the history
Fixes #10594
  • Loading branch information
bep committed Jan 17, 2023
1 parent c6b3887 commit 2fb40ec
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
5 changes: 5 additions & 0 deletions tpl/internal/templatefuncsRegistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -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] == "" {
Expand Down
12 changes: 11 additions & 1 deletion tpl/strings/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
25 changes: 25 additions & 0 deletions tpl/strings/regexp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
33 changes: 33 additions & 0 deletions tpl/strings/regexp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 2fb40ec

Please sign in to comment.