package rext import "regexp" type Regex interface { IsMatch(haystack string) bool MatchFirst(haystack string) (RegexMatch, bool) MatchAll(haystack string) []RegexMatch ReplaceAll(haystack string, repl string, literal bool) string ReplaceAllFunc(haystack string, repl func(string) string) string RemoveAll(haystack string) string GroupCount() int } type regexWrapper struct { rex *regexp.Regexp subnames []string } type RegexMatch struct { haystack string submatchesIndex []int subnames []string } type RegexMatchGroup struct { haystack string start int end int } func W(rex *regexp.Regexp) Regex { return ®exWrapper{rex: rex, subnames: rex.SubexpNames()} } // --------------------------------------------------------------------------------------------------------------------- func (w *regexWrapper) IsMatch(haystack string) bool { return w.rex.MatchString(haystack) } func (w *regexWrapper) MatchFirst(haystack string) (RegexMatch, bool) { res := w.rex.FindStringSubmatchIndex(haystack) if res == nil { return RegexMatch{}, false } return RegexMatch{haystack: haystack, submatchesIndex: res, subnames: w.subnames}, true } func (w *regexWrapper) MatchAll(haystack string) []RegexMatch { resarr := w.rex.FindAllStringSubmatchIndex(haystack, -1) matches := make([]RegexMatch, 0, len(resarr)) for _, res := range resarr { matches = append(matches, RegexMatch{haystack: haystack, submatchesIndex: res, subnames: w.subnames}) } return matches } func (w *regexWrapper) ReplaceAll(haystack string, repl string, literal bool) string { if literal { // do not expand placeholder aka $1, $2, ... return w.rex.ReplaceAllLiteralString(haystack, repl) } else { return w.rex.ReplaceAllString(haystack, repl) } } func (w *regexWrapper) ReplaceAllFunc(haystack string, repl func(string) string) string { return w.rex.ReplaceAllStringFunc(haystack, repl) } func (w *regexWrapper) RemoveAll(haystack string) string { return w.rex.ReplaceAllLiteralString(haystack, "") } // GroupCount returns the amount of groups in this match, does not count group-0 (whole match) func (w *regexWrapper) GroupCount() int { return len(w.subnames) - 1 } // --------------------------------------------------------------------------------------------------------------------- func (m RegexMatch) FullMatch() RegexMatchGroup { return RegexMatchGroup{haystack: m.haystack, start: m.submatchesIndex[0], end: m.submatchesIndex[1]} } // GroupCount returns the amount of groups in this match, does not count group-0 (whole match) func (m RegexMatch) GroupCount() int { return len(m.subnames) - 1 } // GroupByIndex returns the value of a matched group (group 0 == whole match) func (m RegexMatch) GroupByIndex(idx int) RegexMatchGroup { return RegexMatchGroup{haystack: m.haystack, start: m.submatchesIndex[idx*2], end: m.submatchesIndex[idx*2+1]} } // GroupByName returns the value of a matched group (group 0 == whole match) func (m RegexMatch) GroupByName(name string) RegexMatchGroup { for idx, subname := range m.subnames { if subname == name { return RegexMatchGroup{haystack: m.haystack, start: m.submatchesIndex[idx*2], end: m.submatchesIndex[idx*2+1]} } } panic("failed to find regex-group by name") } // --------------------------------------------------------------------------------------------------------------------- func (g RegexMatchGroup) Value() string { return g.haystack[g.start:g.end] } func (g RegexMatchGroup) Start() int { return g.start } func (g RegexMatchGroup) End() int { return g.end } func (g RegexMatchGroup) Range() (int, int) { return g.start, g.end } func (g RegexMatchGroup) Length() int { return g.end - g.start }