github.com/metasources/buildx@v0.0.0-20230418141019-7aa1459cedea/internal/regex_helpers.go (about) 1 package internal 2 3 import "regexp" 4 5 // MatchNamedCaptureGroups takes a regular expression and string and returns all of the named capture group results in a map. 6 // This is only for the first match in the regex. Callers shouldn't be providing regexes with multiple capture groups with the same name. 7 func MatchNamedCaptureGroups(regEx *regexp.Regexp, content string) map[string]string { 8 // note: we are looking across all matches and stopping on the first non-empty match. Why? Take the following example: 9 // input: "cool something to match against" pattern: `((?P<name>match) (?P<version>against))?`. Since the pattern is 10 // encapsulated in an optional capture group, there will be results for each character, but the results will match 11 // on nothing. The only "true" match will be at the end ("match against"). 12 allMatches := regEx.FindAllStringSubmatch(content, -1) 13 var results map[string]string 14 for _, match := range allMatches { 15 // fill a candidate results map with named capture group results, accepting empty values, but not groups with 16 // no names 17 for nameIdx, name := range regEx.SubexpNames() { 18 if nameIdx > len(match) || len(name) == 0 { 19 continue 20 } 21 if results == nil { 22 results = make(map[string]string) 23 } 24 results[name] = match[nameIdx] 25 } 26 // note: since we are looking for the first best potential match we should stop when we find the first one 27 // with non-empty results. 28 if !isEmptyMap(results) { 29 break 30 } 31 } 32 return results 33 } 34 35 func isEmptyMap(m map[string]string) bool { 36 if len(m) == 0 { 37 return true 38 } 39 for _, value := range m { 40 if value != "" { 41 return false 42 } 43 } 44 return true 45 }