import (
"fmt"
+ "regexp"
"strings"
+ "sync"
"github.com/gohugoio/hugo/compare"
)
}
return false
}
+
+// regexpCache represents a cache of regexp objects protected by a mutex.
+type regexpCache struct {
+ mu sync.RWMutex
+ re map[string]*regexp.Regexp
+}
+
+func (rc *regexpCache) getOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
+ var ok bool
+
+ if re, ok = rc.get(pattern); !ok {
+ re, err = regexp.Compile(pattern)
+ if err != nil {
+ return nil, err
+ }
+ rc.set(pattern, re)
+ }
+
+ return re, nil
+}
+
+func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
+ rc.mu.RLock()
+ re, ok = rc.re[key]
+ rc.mu.RUnlock()
+ return
+}
+
+func (rc *regexpCache) set(key string, re *regexp.Regexp) {
+ rc.mu.Lock()
+ rc.re[key] = re
+ rc.mu.Unlock()
+}
+
+var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}
+
+// GetOrCompileRegexp retrieves a regexp object from the cache based upon the pattern.
+// If the pattern is not found in the cache, the pattern is compiled and added to
+// the cache.
+func GetOrCompileRegexp(pattern string) (re *regexp.Regexp, err error) {
+ return reCache.getOrCompileRegexp(pattern)
+}
package hstrings
import (
+ "regexp"
"testing"
qt "github.com/frankban/quicktest"
c.Assert(StringEqualFold(s1).Eq("b"), qt.Equals, false)
}
+
+func TestGetOrCompileRegexp(t *testing.T) {
+ c := qt.New(t)
+
+ re, err := GetOrCompileRegexp(`\d+`)
+ c.Assert(err, qt.IsNil)
+ c.Assert(re.MatchString("123"), qt.Equals, true)
+
+}
+
+func BenchmarkGetOrCompileRegexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ GetOrCompileRegexp(`\d+`)
+ }
+}
+
+func BenchmarkCompileRegexp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ regexp.MustCompile(`\d+`)
+ }
+}
package strings
import (
- "regexp"
- "sync"
-
+ "github.com/gohugoio/hugo/common/hstrings"
"github.com/spf13/cast"
)
// FindRE returns a list of strings that match the regular expression. By default all matches
// will be included. The number of matches can be limited with an optional third parameter.
func (ns *Namespace) FindRE(expr string, content any, limit ...any) ([]string, error) {
- re, err := reCache.Get(expr)
+ re, err := hstrings.GetOrCompileRegexp(expr)
if err != nil {
return nil, err
}
// 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)
+ re, err := hstrings.GetOrCompileRegexp(expr)
if err != nil {
return nil, err
}
}
}
- re, err := reCache.Get(sp)
+ re, err := hstrings.GetOrCompileRegexp(sp)
if err != nil {
return "", err
}
return re.ReplaceAllString(str, sr)
}), nil
}
-
-// regexpCache represents a cache of regexp objects protected by a mutex.
-type regexpCache struct {
- mu sync.RWMutex
- re map[string]*regexp.Regexp
-}
-
-// Get retrieves a regexp object from the cache based upon the pattern.
-// If the pattern is not found in the cache, create one
-func (rc *regexpCache) Get(pattern string) (re *regexp.Regexp, err error) {
- var ok bool
-
- if re, ok = rc.get(pattern); !ok {
- re, err = regexp.Compile(pattern)
- if err != nil {
- return nil, err
- }
- rc.set(pattern, re)
- }
-
- return re, nil
-}
-
-func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
- rc.mu.RLock()
- re, ok = rc.re[key]
- rc.mu.RUnlock()
- return
-}
-
-func (rc *regexpCache) set(key string, re *regexp.Regexp) {
- rc.mu.Lock()
- rc.re[key] = re
- rc.mu.Unlock()
-}
-
-var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}