Skip to content

Commit

Permalink
tpl: Add replaceRE function
Browse files Browse the repository at this point in the history
This commit addes a `replaceRE` template function.  Regexp patterns are compiled
once and cached.
  • Loading branch information
moorereason committed Mar 10, 2016
1 parent 2d0650d commit 18c1d44
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
7 changes: 7 additions & 0 deletions docs/content/templates/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions tpl/template_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"math/rand"
"os"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -1228,6 +1229,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
Expand Down Expand Up @@ -1714,6 +1746,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,
Expand Down
21 changes: 21 additions & 0 deletions tpl/template_funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit 18c1d44

Please sign in to comment.