package rext import ( "gogs.mikescher.com/BlackForestBytes/goext/langext" "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 } type OptRegexMatchGroup struct { v *RegexMatchGroup } 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 (panics if not found!) 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") } // GroupByName returns the value of a matched group (returns empty OptRegexMatchGroup if not found) func (m RegexMatch) GroupByNameOrEmpty(name string) OptRegexMatchGroup { for idx, subname := range m.subnames { if subname == name { return OptRegexMatchGroup{&RegexMatchGroup{haystack: m.haystack, start: m.submatchesIndex[idx*2], end: m.submatchesIndex[idx*2+1]}} } } return OptRegexMatchGroup{} } // --------------------------------------------------------------------------------------------------------------------- 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 } // --------------------------------------------------------------------------------------------------------------------- func (g OptRegexMatchGroup) Value() string { return g.v.Value() } func (g OptRegexMatchGroup) ValueOrEmpty() string { if g.v == nil { return "" } return g.v.Value() } func (g OptRegexMatchGroup) ValueOrNil() *string { if g.v == nil { return nil } return langext.Ptr(g.v.Value()) } func (g OptRegexMatchGroup) IsEmpty() bool { return g.v == nil } func (g OptRegexMatchGroup) Exists() bool { return g.v != nil } func (g OptRegexMatchGroup) Start() int { return g.v.Start() } func (g OptRegexMatchGroup) End() int { return g.v.End() } func (g OptRegexMatchGroup) Range() (int, int) { return g.v.Range() } func (g OptRegexMatchGroup) Length() int { return g.v.Length() }