tpl: Add replaceRE function

This commit addes a `replaceRE` template function.  Regexp patterns are compiled
once and cached.
This commit is contained in:
Cameron Moore 2016-02-08 16:57:52 -06:00 committed by Bjørn Erik Pedersen
parent e9008b91fa
commit b8d3651242
3 changed files with 61 additions and 0 deletions

View file

@ -451,6 +451,13 @@ Replaces all occurrences of the search string with the replacement string.
e.g. `{{ replace "Batman and Robin" "Robin" "Catwoman" }}` → "Batman and Catwoman"
### replaceRE
Replaces all occurrences of a regular expression with the replacement pattern.
e.g. `{{ replaceRE "^https?://([^/]+).*" "$1" "http://gohugo.io/docs" }}` → "gohugo.io"
e.g. `{{ "http://gohugo.io/docs" | replaceRE "^https?://([^/]+).*" "$1" }}` → "gohugo.io"
### safeHTML
Declares the provided string as a "safe" HTML document fragment
so Go html/template will not filter it. It should not be used

View file

@ -29,6 +29,7 @@ import (
"math/rand"
"os"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
@ -1230,6 +1231,37 @@ func replace(a, b, c interface{}) (string, error) {
return strings.Replace(aStr, bStr, cStr, -1), nil
}
var regexpCache = make(map[string]*regexp.Regexp)
// replaceRE exposes a regular expression replacement function to the templates.
func replaceRE(pattern, repl, src interface{}) (_ string, err error) {
patternStr, err := cast.ToStringE(pattern)
if err != nil {
return
}
replStr, err := cast.ToStringE(repl)
if err != nil {
return
}
srcStr, err := cast.ToStringE(src)
if err != nil {
return
}
if _, ok := regexpCache[patternStr]; !ok {
re, err2 := regexp.Compile(patternStr)
if err2 != nil {
return "", err2
}
regexpCache[patternStr] = re
}
return regexpCache[patternStr].ReplaceAllString(srcStr, replStr), err
}
// dateFormat converts the textual representation of the datetime string into
// the other form or returns it of the time.Time value. These are formatted
// with the layout string
@ -1717,6 +1749,7 @@ func init() {
"relURL": func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) },
"relref": relRef,
"replace": replace,
"replaceRE": replaceRE,
"safeCSS": safeCSS,
"safeHTML": safeHTML,
"safeJS": safeJS,

View file

@ -1781,6 +1781,27 @@ func TestReplace(t *testing.T) {
assert.NotNil(t, e, "tstNoStringer cannot be converted to string")
}
func TestReplaceRE(t *testing.T) {
for i, val := range []struct {
pattern string
repl string
src string
expect string
ok bool
}{
{"^https?://([^/]+).*", "$1", "http://gohugo.io/docs", "gohugo.io", true},
{"^https?://([^/]+).*", "$2", "http://gohugo.io/docs", "", true},
{"(ab)", "AB", "aabbaab", "aABbaAB", true},
{"(ab", "AB", "aabb", "", false}, // invalid re
} {
v, err := replaceRE(val.pattern, val.repl, val.src)
if (err == nil) != val.ok {
t.Errorf("[%d] %s", i, err)
}
assert.Equal(t, val.expect, v)
}
}
func TestTrim(t *testing.T) {
for i, this := range []struct {