I'm using Named Captures
in PowerShell
. But the following example is not returning all matches. All the lines in the following code return correct output - except the lines 7 and 8. I was expecting $Matches.1
and $Matches.2
to return v
and A
respectively. But these two lines of code return nothing.
Question: What I may be missing here or maybe not correctly understanding here?
Ref: Lates version 7.4 of PowerShell
PS> $string = 'The last logged on user was A\v'
PS> $string -match 'was (?<domain>.+)\\(?<user>.+)'
PS> $Matches.domain #returns A
PS> $Matches.user #returns v
PS> $Matches.count #returns 3
PS> $Matches.0 #returns was A\v
PS> $Matches.1 #returns nothing
PS> $Matches.2 #returns nothing
PS> $Matches #returns the following output
Name | Value |
---|---|
domain | A |
user | v |
0 | was A\v |
The automatic
$Matches
variable is a hashtable whose entries are populated as follows:The entry with key (index)
0
(type[int]
) is always present, representing the whole match.Additional entries are only populated if there are capture groups in the regex, as follows:
Any named capture group (e.g.
(?<domain>.+)
) is represented by an entry with a key of the same name (type[string]
) - only (it doesn't also get a positional entry - see below).$Matches.domain
or, alternatively,$Matches['domain']
, returns the substring matched by the example capture group, if any.Any - remaining or only - unnamed and therefore positional capture groups (e.g.
(.+)
) are represented in order, with indices, namely as entries with[int]
-typed keys starting with1
.$Matches.1
or, alternatively,$Matches[1]
, would return the substring that the example capture group matched, assuming it is the first positional (unnamed) one in the regex.It follows from the above that in your case
$Matches
only has'domain'
and'user'
entries beyond the always-present0
entry, because only named capture groups, with these names, are present.Also note that the fact that
$Matches
is implemented as a[hashtable]
implies that its entries are inherently unordered - thus, you cannot rely on the enumeration order of the entries to be meaningful (via.GetEnumerator()
for the entries as a whole, or via.Keys
or.Values
for the keys and values, respectively), and even the entries with keys that are conceptually indices - for the whole match and any unnamed / positional capture groups - are typically not reflected in their numerical order.Important considerations of
$Matches
use:It is automatically populated by:
-match
, the regular-expression matching operator:Only if the LHS is a single string (object) and a match is found, i.e. only when
-match
returns$true
Notably, a preexisting
$Matches
result is left untouched if$false
is returned, so$Matches
should only be consulted after receiving$true
.-match
only ever looks for one match in the input string.-matchall
operator.A simple example:
By contrast, with array-valued LHS,
-match
- like other comparison operators - acts as a filter that returns the sub-array of matching input strings, and doesn't populate$Matches
at all (nor resets any previous results).the
switch
statement, if used with the-Regex
switch:Specifically, string-based branch conditionals are then treated as regexes and the associated action block - which is only entered in case of a match - then has
$Matches
populated.A simple example: