regexp.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package utils
  3. import (
  4. "fmt"
  5. "regexp"
  6. "strings"
  7. )
  8. var _ = fmt.Print
  9. var pat_cache = NewLRUCache[string, *regexp.Regexp](128)
  10. type SubMatch struct {
  11. Text string
  12. Start, End int
  13. }
  14. func Compile(pat string) (*regexp.Regexp, error) {
  15. return pat_cache.GetOrCreate(pat, regexp.Compile)
  16. }
  17. func MustCompile(pat string) *regexp.Regexp {
  18. return pat_cache.MustGetOrCreate(pat, regexp.MustCompile)
  19. }
  20. func ReplaceAll(cpat *regexp.Regexp, str string, repl func(full_match string, groupdict map[string]SubMatch) string) string {
  21. result := strings.Builder{}
  22. result.Grow(len(str) + 256)
  23. last_index := 0
  24. matches := cpat.FindAllStringSubmatchIndex(str, -1)
  25. names := cpat.SubexpNames()
  26. groupdict := make(map[string]SubMatch, len(names))
  27. for _, v := range matches {
  28. match_start, match_end := v[0], v[1]
  29. full_match := str[match_start:match_end]
  30. for k := range groupdict {
  31. delete(groupdict, k)
  32. }
  33. for i, name := range names {
  34. idx := 2 * i
  35. if v[idx] > -1 && v[idx+1] > -1 {
  36. groupdict[name] = SubMatch{Text: str[v[idx]:v[idx+1]], Start: v[idx], End: v[idx+1]}
  37. }
  38. }
  39. result.WriteString(str[last_index:match_start])
  40. result.WriteString(repl(full_match, groupdict))
  41. last_index = match_end
  42. }
  43. result.WriteString(str[last_index:])
  44. return result.String()
  45. }