mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
simplify MatchNamedCaptureGroups implementation
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
f438ee974c
commit
f9d49885ae
@ -3,37 +3,43 @@ package internal
|
|||||||
import "regexp"
|
import "regexp"
|
||||||
|
|
||||||
// MatchNamedCaptureGroups takes a regular expression and string and returns all of the named capture group results in a map.
|
// MatchNamedCaptureGroups takes a regular expression and string and returns all of the named capture group results in a map.
|
||||||
// Note: this is only for the first match in the regex.
|
// This is only for the first match in the regex. Callers shouldn't be providing regexes with multiple capture groups with the same name.
|
||||||
func MatchNamedCaptureGroups(regEx *regexp.Regexp, content string) map[string]string {
|
func MatchNamedCaptureGroups(regEx *regexp.Regexp, content string) map[string]string {
|
||||||
// note: we are looking across all matches and stopping on the first non-empty match. Why? Take the following example:
|
// note: we are looking across all matches and stopping on the first non-empty match. Why? Take the following example:
|
||||||
// input: "cool something to match against" pattern: `((?P<name>match) (?P<version>against))?`. Since the pattern is
|
// input: "cool something to match against" pattern: `((?P<name>match) (?P<version>against))?`. Since the pattern is
|
||||||
// encapsulated in an optional capture group, there will be results for each character, but the results will match
|
// encapsulated in an optional capture group, there will be results for each character, but the results will match
|
||||||
// on nothing. The only "true" match will be at the end ("match against").
|
// on nothing. The only "true" match will be at the end ("match against").
|
||||||
allMatches := regEx.FindAllStringSubmatch(content, -1)
|
allMatches := regEx.FindAllStringSubmatch(content, -1)
|
||||||
for matchIdx, match := range allMatches {
|
var results map[string]string
|
||||||
|
for _, match := range allMatches {
|
||||||
// fill a candidate results map with named capture group results, accepting empty values, but not groups with
|
// fill a candidate results map with named capture group results, accepting empty values, but not groups with
|
||||||
// no names
|
// no names
|
||||||
results := make(map[string]string)
|
|
||||||
for nameIdx, name := range regEx.SubexpNames() {
|
for nameIdx, name := range regEx.SubexpNames() {
|
||||||
if nameIdx <= len(match) && len(name) > 0 {
|
if nameIdx > len(match) || len(name) == 0 {
|
||||||
results[name] = match[nameIdx]
|
continue
|
||||||
}
|
}
|
||||||
|
if results == nil {
|
||||||
|
results = make(map[string]string)
|
||||||
|
}
|
||||||
|
results[name] = match[nameIdx]
|
||||||
}
|
}
|
||||||
// note: since we are looking for the first best potential match we should stop when we find the first one
|
// note: since we are looking for the first best potential match we should stop when we find the first one
|
||||||
// with non-empty results.
|
// with non-empty results.
|
||||||
if len(results) > 0 {
|
if !isEmptyMap(results) {
|
||||||
foundNonEmptyValue := false
|
break
|
||||||
for _, value := range results {
|
|
||||||
if value != "" {
|
|
||||||
foundNonEmptyValue = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// return the first non-empty result, or if this is the last match, the results that were found.
|
|
||||||
if foundNonEmptyValue || matchIdx == len(allMatches)-1 {
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEmptyMap(m map[string]string) bool {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, value := range m {
|
||||||
|
if value != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user