From bae0abe9606795f952634a39417ab737cdf0225e Mon Sep 17 00:00:00 2001 From: brent saner Date: Tue, 12 Aug 2025 00:06:51 -0400 Subject: [PATCH] v1.9.3 IMPROVED: * Better documentation for remap --- remap/doc.go | 2 +- remap/funcs_remap.go | 161 +++++++++++++++++++++++++++++++++++++++++-- remap/types.go | 18 +++-- 3 files changed, 166 insertions(+), 15 deletions(-) diff --git a/remap/doc.go b/remap/doc.go index da941a7..c8dcfb1 100644 --- a/remap/doc.go +++ b/remap/doc.go @@ -1,4 +1,4 @@ /* -Package remap provides convenience functions around regular expressions. +Package remap provides convenience functions around regular expressions, primarily offering maps for named capture groups. */ package remap diff --git a/remap/funcs_remap.go b/remap/funcs_remap.go index 690a44a..ac21e0c 100644 --- a/remap/funcs_remap.go +++ b/remap/funcs_remap.go @@ -1,11 +1,67 @@ package remap /* - Map returns a map[string] for regexes with named capture groups matched in bytes b. - Note that this supports non-unique group names; regexp.Regexp allows for patterns with multiple groups - using the same group name. Each match for each group is in a slice keyed under that group name, with - that slice ordered by the indexing done by the regex match itself. - matches and/or its values may be nil or empty under the following condition tree: +Map returns a map[string][] for regexes with named capture groups matched in bytes b. +Note that this supports non-unique group names; [regexp.Regexp] allows for patterns with multiple groups +using the same group name (though your IDE might complain; I know GoLand does). + +Each match for each group is in a slice keyed under that group name, with that slice +ordered by the indexing done by the regex match itself. + +In summary, the parameters are as follows: + +# inclNoMatch + +If true, then attempt to return a non-nil matches (as long as b isn't nil). +Group keys will be populated and explicitly defined as nil. + +For example, if a pattern + + ^(?Pfoo)(?Pbar)(?Pbaz)$ + +is provided but b does not match then matches will be: + + map[string][][]byte{ + "g1": nil, + "g2": nil, + } + +# inclNoMatchStrict + +If true (and inclNoMatch is true), instead of a single nil the group's values will be +a slice of nil values explicitly matching the number of times the group name is specified +in the pattern. + +For example, if a pattern: + + ^(?Pfoo)(?Pbar)(?Pbaz)$ + +is provided but b does not match then matches will be: + + map[string][][]byte{ + "g1": [][]byte{ + nil, + nil, + }, + "g2": [][]byte{ + nil, + }, + } + +# mustMatch + +If true, matches will be nil if the entirety of b does not match the pattern (and thus +no capture groups matched) (overrides inclNoMatch) -- explicitly: + + matches == nil + +Otherwise if false (and assuming inclNoMatch is false), matches will be: + + map[string][][]byte{}{} + +# Condition Tree + +In detail, matches and/or its values may be nil or empty under the following condition tree: IF b is nil: THEN matches will always be nil @@ -148,9 +204,100 @@ func (r *ReMap) Map(b []byte, inclNoMatch, inclNoMatchStrict, mustMatch bool) (m } /* - MapString is exactly like ReMap.Map(), but operates on (and returns) strings instead. (matches will always be nil if s == ``.) +MapString is exactly like ReMap.Map(), but operates on (and returns) strings instead. +(matches will always be nil if s == “.) - A small deviation, though; empty strings instead of nils (because duh) will occupy placeholders (if inclNoMatchStrict is specified). +A small deviation, though; empty strings instead of nils (because duh) will occupy slice placeholders (if `inclNoMatchStrict` is specified). +This unfortunately *does not provide any indication* if an empty string positively matched the pattern (a "hit") or if it was simply +not matched at all (a "miss"). If you need definitive determination between the two conditions, it is instead recommended to either +*not* use inclNoMatchStrict or to use ReMap.Map() instead and convert any non-nil values to strings after. + +Particularly: + +# inclNoMatch + +If true, then attempt to return a non-nil matches (as long as s isn't empty). +Group keys will be populated and explicitly defined as nil. + +For example, if a pattern + + ^(?Pfoo)(?Pbar)(?Pbaz)$ + +is provided but s does not match then matches will be: + + map[string][]string{ + "g1": nil, + "g2": nil, + } + +# inclNoMatchStrict + +If true (and inclNoMatch is true), instead of a single nil the group's values will be +a slice of eempty string values explicitly matching the number of times the group name is specified +in the pattern. + +For example, if a pattern: + + ^(?Pfoo)(?Pbar)(?Pbaz)$ + +is provided but s does not match then matches will be: + + map[string][]string{ + "g1": []string{ + "", + "", + }, + "g2": []string{ + "", + }, + } + +# mustMatch + +If true, matches will be nil if the entirety of s does not match the pattern (and thus +no capture groups matched) (overrides inclNoMatch) -- explicitly: + + matches == nil + +Otherwise if false (and assuming inclNoMatch is false), matches will be: + + map[string][]string{}{} + +# Condition Tree + +In detail, matches and/or its values may be nil or empty under the following condition tree: + + IF s is empty: + THEN matches will always be nil + ELSE: + IF all of s does not match pattern + IF mustMuch is true + THEN matches == nil + ELSE + THEN matches == map[string][]string{} (non-nil but empty) + ELSE IF pattern has no named capture groups + IF inclNoMatch is true + THEN matches == map[string][]string{} (non-nil but empty) + ELSE + THEN matches == nil + ELSE + IF there are no named group matches + IF inclNoMatch is true + THEN matches is non-nil; matches[, ...] is/are defined but nil (_, ok = matches[]; ok == true) + ELSE + THEN matches == nil + ELSE + IF does not have a match + IF inclNoMatch is true + IF inclNoMatchStrict is true + THEN matches[] is defined and non-nil, but populated with placeholder nils + (matches[] == []string{""[, ""...]}) + ELSE + THEN matches[] is guaranteed defined but may be nil (_, ok = matches[]; ok == true) + ELSE + THEN matches[] is not defined (_, ok = matches[]; ok == false) + ELSE + matches[] == []{[, ...]} */ func (r *ReMap) MapString(s string, inclNoMatch, inclNoMatchStrict, mustMatch bool) (matches map[string][]string) { diff --git a/remap/types.go b/remap/types.go index bf304db..dba0f0e 100644 --- a/remap/types.go +++ b/remap/types.go @@ -1,7 +1,7 @@ package remap import ( - `regexp` + "regexp" ) type ( @@ -10,14 +10,18 @@ type ( *regexp.Regexp } + // TODO? /* ExplicitStringMatch is used with ReMap.MapStringExplicit to indicate if a capture group result is a hit (a group matched, but e.g. the match value is empty string) - or not (a group did not match) + or not (a group did not match). + */ + /* + ExplicitStringMatch struct { + Group string + IsMatch bool + Value string + } + */ - ExplicitStringMatch struct { - Group string - IsMatch bool - Value string - } )