ref: 5bfe16ef8d37b7030da9bdf1b68bdb18ff0079a3
parent: 54750b078059734c3f2047ae3f56cac64a9f0666
author: digitalcraftsman <[email protected]>
date: Tue Apr 5 14:02:18 EDT 2016
tpl: Add findRE template func
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -474,6 +474,36 @@
e.g. `{{ "cat" | pluralize }}` → "cats"
+### findRE
+Returns a list of strings that match the regular expression. By default all matches will be included. The number of matches can be limitted with an optional third parameter.
+
+The example below returns a list of all second level headers (`<h2>`) in the content:
+
+ {{ findRE "<h2.*?>(.|\n)*?</h2>" .Content }}
+
+We can limit the number of matches in that list with a third parameter. Let's say we want to have at most one match (or none if no substring matched):
+
+ {{ findRE "<h2.*?>(.|\n)*?</h2>" .Content 1 }}
+ <!-- returns ["<h2 id="#foo">Foo</h2>"] -->
+
+`findRe` allows us to build an automatically generated table of contents that could be used for a simple scrollspy:
+
+ {{ $headers := findRE "<h2.*?>(.|\n)*?</h2>" .Content }}
+
+ {{ if ge (len $headers) 1 }}
+ <ul>
+ {{ range $headers }}
+ <li>
+ <a href="#{{ . | plainify | urlize }}">
+ {{ . | plainify }}
+ </a>
+ </li>
+ {{ end }}
+ </ul>
+ {{ end }}
+
+First, we try to find all second-level headers and generate a list if at least one header was found. `plainify` strips the HTML and `urlize` converts the header into an a valid URL.
+
### replace
Replaces all occurrences of the search string with the replacement string.
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -437,6 +437,22 @@
return seqv.Slice(0, limitv).Interface(), nil
}
+// findRE returns a list of strings that match the regular expression. By default all matches
+// will be included. The number of matches can be limitted with an optional third parameter.
+func findRE(expr string, content interface{}, limit ...int) ([]string, error) {
+ re, err := reCache.Get(expr)
+ if err != nil {
+ return nil, err
+ }
+
+ conv := cast.ToString(content)
+ if len(limit) > 0 {
+ return re.FindAllString(conv, limit[0]), nil
+ }
+
+ return re.FindAllString(conv, -1), nil
+}
+
// last returns the last N items in a rangeable list.
func last(limit interface{}, seq interface{}) (interface{}, error) {
if limit == nil || seq == nil {
@@ -1729,6 +1745,7 @@
"echoParam": returnWhenSet,
"emojify": emojify,
"eq": eq,
+ "findRE": findRE,
"first": first,
"ge": ge,
"getCSV": getCSV,
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -89,6 +89,7 @@
div: {{div 6 3}}
emojify: {{ "I :heart: Hugo" | emojify }}
eq: {{ if eq .Section "blog" }}current{{ end }}
+findRE: {{ findRE "[G|g]o" "Hugo is a static side generator written in Go." 1 }}
hasPrefix 1: {{ hasPrefix "Hugo" "Hu" }}
hasPrefix 2: {{ hasPrefix "Hugo" "Fu" }}
in: {{ if in "this string contains a substring" "substring" }}Substring found!{{ end }}
@@ -138,6 +139,7 @@
div: 2
emojify: I ❤️ Hugo
eq: current
+findRE: [go]
hasPrefix 1: true
hasPrefix 2: false
in: Substring found!
@@ -1798,6 +1800,30 @@
t.Errorf("[%d] %s", i, err)
}
assert.Equal(t, val.expect, v)
+ }
+}
+
+func TestFindRE(t *testing.T) {
+ for i, this := range []struct {
+ expr string
+ content string
+ limit int
+ expect []string
+ ok bool
+ }{
+ {"[G|g]o", "Hugo is a static side generator written in Go.", 2, []string{"go", "Go"}, true},
+ {"[G|g]o", "Hugo is a static side generator written in Go.", -1, []string{"go", "Go"}, true},
+ {"[G|g]o", "Hugo is a static side generator written in Go.", 1, []string{"go"}, true},
+ {"[G|g]o", "Hugo is a static side generator written in Go.", 0, []string(nil), true},
+ {"[G|go", "Hugo is a static side generator written in Go.", 0, []string(nil), false},
+ } {
+ res, err := findRE(this.expr, this.content, this.limit)
+
+ if err != nil && this.ok {
+ t.Errorf("[%d] returned an unexpected error: %s", i, err)
+ }
+
+ assert.Equal(t, this.expect, res)
}
}