hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

regexp.go (2916B)

    1 // Copyright 2017 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package strings
   15 
   16 import (
   17 	"regexp"
   18 	"sync"
   19 
   20 	"github.com/spf13/cast"
   21 )
   22 
   23 // FindRE returns a list of strings that match the regular expression. By default all matches
   24 // will be included. The number of matches can be limited with an optional third parameter.
   25 func (ns *Namespace) FindRE(expr string, content any, limit ...any) ([]string, error) {
   26 	re, err := reCache.Get(expr)
   27 	if err != nil {
   28 		return nil, err
   29 	}
   30 
   31 	conv, err := cast.ToStringE(content)
   32 	if err != nil {
   33 		return nil, err
   34 	}
   35 
   36 	if len(limit) == 0 {
   37 		return re.FindAllString(conv, -1), nil
   38 	}
   39 
   40 	lim, err := cast.ToIntE(limit[0])
   41 	if err != nil {
   42 		return nil, err
   43 	}
   44 
   45 	return re.FindAllString(conv, lim), nil
   46 }
   47 
   48 // ReplaceRE returns a copy of s, replacing all matches of the regular
   49 // expression pattern with the replacement text repl. The number of replacements
   50 // can be limited with an optional fourth parameter.
   51 func (ns *Namespace) ReplaceRE(pattern, repl, s any, n ...any) (_ string, err error) {
   52 	sp, err := cast.ToStringE(pattern)
   53 	if err != nil {
   54 		return
   55 	}
   56 
   57 	sr, err := cast.ToStringE(repl)
   58 	if err != nil {
   59 		return
   60 	}
   61 
   62 	ss, err := cast.ToStringE(s)
   63 	if err != nil {
   64 		return
   65 	}
   66 
   67 	nn := -1
   68 	if len(n) > 0 {
   69 		nn, err = cast.ToIntE(n[0])
   70 		if err != nil {
   71 			return
   72 		}
   73 	}
   74 
   75 	re, err := reCache.Get(sp)
   76 	if err != nil {
   77 		return "", err
   78 	}
   79 
   80 	return re.ReplaceAllStringFunc(ss, func(str string) string {
   81 		if nn == 0 {
   82 			return str
   83 		}
   84 
   85 		nn -= 1
   86 		return re.ReplaceAllString(str, sr)
   87 	}), nil
   88 }
   89 
   90 // regexpCache represents a cache of regexp objects protected by a mutex.
   91 type regexpCache struct {
   92 	mu sync.RWMutex
   93 	re map[string]*regexp.Regexp
   94 }
   95 
   96 // Get retrieves a regexp object from the cache based upon the pattern.
   97 // If the pattern is not found in the cache, create one
   98 func (rc *regexpCache) Get(pattern string) (re *regexp.Regexp, err error) {
   99 	var ok bool
  100 
  101 	if re, ok = rc.get(pattern); !ok {
  102 		re, err = regexp.Compile(pattern)
  103 		if err != nil {
  104 			return nil, err
  105 		}
  106 		rc.set(pattern, re)
  107 	}
  108 
  109 	return re, nil
  110 }
  111 
  112 func (rc *regexpCache) get(key string) (re *regexp.Regexp, ok bool) {
  113 	rc.mu.RLock()
  114 	re, ok = rc.re[key]
  115 	rc.mu.RUnlock()
  116 	return
  117 }
  118 
  119 func (rc *regexpCache) set(key string, re *regexp.Regexp) {
  120 	rc.mu.Lock()
  121 	rc.re[key] = re
  122 	rc.mu.Unlock()
  123 }
  124 
  125 var reCache = regexpCache{re: make(map[string]*regexp.Regexp)}