github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/utils/vdutil/regexp.go (about)

     1  package vdutil
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"regexp"
     7  
     8  	"github.com/jxskiss/gopkg/v2/perf/lru"
     9  )
    10  
    11  var reCache lru.Interface[string, *regexp.Regexp]
    12  
    13  // EnableRegexpCache sets an LRU cache to cache compiled regular expressions.
    14  func EnableRegexpCache(cache lru.Interface[string, *regexp.Regexp]) {
    15  	reCache = cache
    16  }
    17  
    18  type RegexpOrString interface {
    19  	*regexp.Regexp | string
    20  }
    21  
    22  // MatchRegexp validates value match the regular expression pattern.
    23  // pattern can be either a string or a compiled *regexp.Regexp.
    24  //
    25  // If pattern is a string and cache is enabled by calling EnableRegexpCache,
    26  // the compiled regular expression will be cached for reuse.
    27  func MatchRegexp[T RegexpOrString](name string, pattern T, value string) RuleFunc {
    28  	re, isRegexp := any(pattern).(*regexp.Regexp)
    29  	if isRegexp {
    30  		return func(ctx context.Context, result *Result) (any, error) {
    31  			var err error
    32  			match := re.MatchString(value)
    33  			if !match {
    34  				err = &ValidationError{Name: name, Err: fmt.Errorf("value %q not match regexp", value)}
    35  			}
    36  			return value, err
    37  		}
    38  	}
    39  
    40  	return func(ctx context.Context, result *Result) (any, error) {
    41  		var err error
    42  		reStr := any(pattern).(string)
    43  		if reCache != nil {
    44  			re, _, _ = reCache.Get(reStr)
    45  		}
    46  		if re == nil {
    47  			re, err = regexp.Compile(reStr)
    48  			if err != nil {
    49  				return value, fmt.Errorf("cannot compile regexp %q: %w", reStr, err)
    50  			}
    51  			if reCache != nil {
    52  				reCache.Set(reStr, re, 0)
    53  			}
    54  		}
    55  		match := re.MatchString(value)
    56  		if !match {
    57  			err = &ValidationError{Name: name, Err: fmt.Errorf("value %q not match regexp", value)}
    58  		}
    59  		return value, err
    60  	}
    61  }