shithub: hugo

Download patch

ref: b8d3651242947bbea46df8d6a9f0477406070019
parent: e9008b91fa0d5b0cc79c1133cd3658134ed6777d
author: Cameron Moore <[email protected]>
date: Mon Feb 8 11:57:52 EST 2016

tpl: Add replaceRE function

This commit addes a `replaceRE` template function.  Regexp patterns are compiled
once and cached.

--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -451,6 +451,13 @@
 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
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -29,6 +29,7 @@
 	"math/rand"
 	"os"
 	"reflect"
+	"regexp"
 	"sort"
 	"strconv"
 	"strings"
@@ -1230,6 +1231,37 @@
 	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 @@
 		"relURL":       func(a string) template.HTML { return template.HTML(helpers.RelURL(a)) },
 		"relref":       relRef,
 		"replace":      replace,
+		"replaceRE":    replaceRE,
 		"safeCSS":      safeCSS,
 		"safeHTML":     safeHTML,
 		"safeJS":       safeJS,
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1781,6 +1781,27 @@
 	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 {