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
$Matchesvariable 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.domainor, 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.1or, 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
$Matchesonly has'domain'and'user'entries beyond the always-present0entry, because only named capture groups, with these names, are present.Also note that the fact that
$Matchesis 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.Keysor.Valuesfor 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
$Matchesuse: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
-matchreturns$trueNotably, a preexisting
$Matchesresult is left untouched if$falseis returned, so$Matchesshould only be consulted after receiving$true.-matchonly ever looks for one match in the input string.-matchalloperator.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$Matchesat all (nor resets any previous results).the
switchstatement, if used with the-Regexswitch: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
$Matchespopulated.A simple example: