github.com/iDigitalFlame/xmt@v0.5.4/util/text/r_regexp.go (about)

     1  //go:build regexp
     2  // +build regexp
     3  
     4  // Copyright (C) 2020 - 2023 iDigitalFlame
     5  //
     6  // This program is free software: you can redistribute it and/or modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // any later version.
    10  //
    11  // This program is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    18  //
    19  
    20  package text
    21  
    22  import (
    23  	"regexp"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/iDigitalFlame/xmt/util"
    28  )
    29  
    30  type inverseRegexp string
    31  
    32  // String parses this MatchString value and will preform any replacements and
    33  // fill any variables contained.
    34  func (s Matcher) String() string {
    35  	if len(s) == 0 {
    36  		return string(s)
    37  	}
    38  	m := regxBuild.FindAllStringSubmatchIndex(string(s), -1)
    39  	if len(m) == 0 {
    40  		return string(s)
    41  	}
    42  	var (
    43  		l   int
    44  		err error
    45  		b   = builders.Get().(*util.Builder)
    46  	)
    47  	b.Grow(len(s))
    48  	for x, v, c := 0, 0, ""; x < len(m); x++ {
    49  		if m[x][0] < 0 || m[x][1] < m[x][0] {
    50  			continue
    51  		}
    52  		if m[x][4] > 0 && m[x][5] > m[x][4] {
    53  			if s[m[x][5]-1] == 'f' {
    54  				v, err = strconv.Atoi(string(s[m[x][4] : m[x][5]-1]))
    55  			} else {
    56  				v, err = strconv.Atoi(string(s[m[x][4]:m[x][5]]))
    57  			}
    58  			if err != nil {
    59  				v = -1
    60  			}
    61  		} else {
    62  			v = -1
    63  		}
    64  		switch {
    65  		case s[m[x][1]-1] == 'n' && s[m[x][1]-2] == 'f' && v > 0:
    66  			c = Rand.StringNumber(v)
    67  		case s[m[x][1]-1] == 'c' && s[m[x][1]-2] == 'f' && v > 0:
    68  			c = Rand.StringCharacters(v)
    69  		case s[m[x][1]-1] == 'u' && s[m[x][1]-2] == 'f' && v > 0:
    70  			c = Rand.StringUpper(v)
    71  		case s[m[x][1]-1] == 'l' && s[m[x][1]-2] == 'f' && v > 0:
    72  			c = Rand.StringLower(v)
    73  		case s[m[x][1]-1] == 's' && s[m[x][1]-2] == 'f' && v > 0:
    74  			c = Rand.String(v)
    75  		case s[m[x][1]-1] == 'd' && s[m[x][1]-2] == 'f' && v >= 0:
    76  			c = util.Uitoa(uint64(v))
    77  		case s[m[x][1]-1] == 'h' && s[m[x][1]-2] == 'f' && v >= 0:
    78  			c = util.Uitoa16(uint64(v))
    79  		case s[m[x][1]-1] == 'd' && v >= 0:
    80  			c = util.Uitoa(uint64(util.FastRandN(v)))
    81  		case s[m[x][1]-1] == 'h' && v >= 0:
    82  			c = util.Uitoa16(uint64(util.FastRandN(v)))
    83  		case s[m[x][1]-1] == 'n' && v > 0:
    84  			c = Rand.StringNumberRange(1, v)
    85  		case s[m[x][1]-1] == 'c' && v > 0:
    86  			c = Rand.StringCharactersRange(1, v)
    87  		case s[m[x][1]-1] == 'u' && v > 0:
    88  			c = Rand.StringUpperRange(1, v)
    89  		case s[m[x][1]-1] == 'l' && v > 0:
    90  			c = Rand.StringLowerRange(1, v)
    91  		case s[m[x][1]-1] == 's' && v > 0:
    92  			c = Rand.StringRange(1, v)
    93  		case s[m[x][1]-1] == 's':
    94  			c = Rand.StringRange(1, 1+int(util.FastRandN(256)))
    95  		case s[m[x][1]-1] == 'd':
    96  			c = util.Uitoa(uint64(util.FastRand()))
    97  		case s[m[x][1]-1] == 'h':
    98  			c = util.Uitoa16(uint64(util.FastRand()))
    99  		default:
   100  			c = string(s[m[x][0]:m[x][1]])
   101  		}
   102  		b.WriteString(string(s[l:m[x][0]]))
   103  		b.WriteString(c)
   104  		c, l = "", m[x][1]
   105  	}
   106  	if l < len(s) {
   107  		b.WriteString(string(s[l:]))
   108  	}
   109  	o := b.String()
   110  	b.Reset()
   111  	builders.Put(b)
   112  	return o
   113  }
   114  func (i inverseRegexp) String() string {
   115  	return string(i)
   116  }
   117  
   118  // MatchEx returns a valid Regexp struct that is guaranteed to match any string
   119  // generated by the Matcher's 'String' function. MatchEx returns an inverse
   120  // matcher if the bool is false.
   121  func (s Matcher) MatchEx(o bool) Regexp {
   122  	if len(s) == 0 {
   123  		return MatchAny
   124  	}
   125  	if s == "*" {
   126  		return MatchAny
   127  	}
   128  	m := regxBuild.FindAllStringSubmatchIndex(string(s), -1)
   129  	if len(m) == 0 {
   130  		if !o {
   131  			return inverseRegexp(s)
   132  		}
   133  		if r, err := regexp.Compile(`^(` + regexp.QuoteMeta(string(s)) + `)$`); err == nil {
   134  			return r
   135  		}
   136  		return MatchNone
   137  	}
   138  	var (
   139  		l   int
   140  		d   string
   141  		err error
   142  		b   = builders.Get().(*util.Builder)
   143  	)
   144  	if b.WriteString("^("); !o {
   145  		d = "^"
   146  	}
   147  	for x, v, c, q := 0, 0, "", ""; x < len(m); x++ {
   148  		if m[x][0] < 0 || m[x][1] < m[x][0] {
   149  			continue
   150  		}
   151  		if m[x][4] > 0 && m[x][5] > m[x][4] {
   152  			if s[m[x][5]-1] == 'f' {
   153  				v, err = strconv.Atoi(string(s[m[x][4] : m[x][5]-1]))
   154  			} else {
   155  				v, err = strconv.Atoi(string(s[m[x][4]:m[x][5]]))
   156  			}
   157  			if err != nil {
   158  				v, q = -1, "0"
   159  			} else {
   160  				q = util.Uitoa(uint64(v))
   161  			}
   162  		} else {
   163  			v = -1
   164  		}
   165  		switch {
   166  		case s[m[x][1]-1] == 'd':
   167  			c = `([` + d + `0-9]+)`
   168  		case s[m[x][1]-1] == 'h':
   169  			c = `([` + d + `a-fA-F0-9]+)`
   170  		case s[m[x][1]-1] == 'n' && s[m[x][1]-2] == 'f' && v > 0:
   171  			c = `([` + d + `0-9]{` + q + `})`
   172  		case s[m[x][1]-1] == 'c' && s[m[x][1]-2] == 'f' && v > 0:
   173  			c = `([` + d + `a-zA-Z]{` + q + `})`
   174  		case s[m[x][1]-1] == 'u' && s[m[x][1]-2] == 'f' && v > 0:
   175  			c = `([` + d + `A-Z]{` + q + `})`
   176  		case s[m[x][1]-1] == 'l' && s[m[x][1]-2] == 'f' && v > 0:
   177  			c = `([` + d + `a-z]{` + q + `})`
   178  		case s[m[x][1]-1] == 's' && s[m[x][1]-2] == 'f' && v > 0:
   179  			c = `([` + d + `a-zA-Z0-9]{` + q + `})`
   180  		case s[m[x][1]-1] == 'n' && v > 0:
   181  			c = `([` + d + `0-9]{1,` + q + `})`
   182  		case s[m[x][1]-1] == 'c' && v > 0:
   183  			c = `([` + d + `a-zA-Z]{1,` + q + `})`
   184  		case s[m[x][1]-1] == 'u' && v > 0:
   185  			c = `([` + d + `A-Z]{1,` + q + `})`
   186  		case s[m[x][1]-1] == 'l' && v > 0:
   187  			c = `([` + d + `a-z]{1,` + q + `})`
   188  		case s[m[x][1]-1] == 's' && v > 0:
   189  			c = `([` + d + `a-zA-Z0-9]{1,` + q + `})`
   190  		case s[m[x][1]-1] == 's':
   191  			c = `([` + d + `a-zA-Z0-9]+)`
   192  		default:
   193  			c = string(s[m[x][0]:m[x][1]])
   194  		}
   195  		b.WriteString(strings.Replace(regexp.QuoteMeta(string(s[l:m[x][0]])), "/", "\\/", -1))
   196  		b.WriteString(c)
   197  		l = m[x][1]
   198  	}
   199  	if l < len(s) {
   200  		b.WriteString(strings.Replace(regexp.QuoteMeta(string(s[l:])), "/", "\\/", -1))
   201  	}
   202  	b.WriteString(")$")
   203  	r, err := regexp.Compile(b.Output())
   204  	if builders.Put(b); err != nil {
   205  		return MatchAny
   206  	}
   207  	return r
   208  }
   209  func (i inverseRegexp) Match(b []byte) bool {
   210  	return string(i) != string(b)
   211  }
   212  func (i inverseRegexp) MatchString(s string) bool {
   213  	return string(i) != s
   214  }