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 }