Note: If hard-coding the result of both regex subexpressions matching is sufficient, simply use:
if ('Catch me if you can' -match '(?=.*Catch)(?=.*me)') { 'Catch me' }
You're trying to:
- match two separate regex subexpressions,
- and report what specific strings they matched only if BOTH matched.
Note:
While it is possible to use a variation of your regex, which concatenates two look-ahead assertions ((?=.*(Catch))(?=.*(me))
), to extract what the two subexpressions of interest captured, the captured substrings would be reported in the order in which the subexpressions are specified in the regex, not in the order in which the substrings appear in the input string. E.g., input string 'me Catch if you can'
would also result in output string 'Catch me'
The following solution uses the [regex]::Match()
.NET API for preserving the input order of the captured substrings by sorting the captures by their starting position in the input string:
$match = [regex]::Match('me Catch if you can', '(?=.*(Catch))(?=.*(me))', 'IgnoreCase')
if ($match.Success) { ($match.Groups | Select-Object -Skip 1 | Sort-Object Position).Value -join ' ' }
Note the use of the IgnoreCase
option, so as to match PowerShell's default behavior of case-insensitive matching.
The above outputs 'me Catch'
, i.e. the captured substrings in the order in which they appear in the input string.
If instead you prefer that the captured substrings be reported in the order in which the subexpressions that matched them appear in the regex ('Catch me'
), simply omit | Sort-Object Position
from the command above.
Alternatively, you then could make your -match
operation work, as follows, by enclosing the subexpressions of interest in (...)
to form capture groups and then accessing the captured substrings via the automatic $Matches
variable - but note that no information about matching positions is then available:
if ('me Catch if you can' -match '(?=.*(Catch))(?=.*(me))') {
$Matches[1..2] -join ' ' # -> 'Catch me'
}
Note that this only works because a single match result captures both substrings of interest, due to the concatenation of two look-ahead assertions ((?=...)
); because -match
only ever looks for one match, the simpler 'Catch|me'
regex would not work, as it would stop matching once either subexpression is found.
See also:
- GitHub issue #7867, which suggests introducing a
-matchall
operator that returns all matches found in the input string.