1

The code below works as is. The commented out lines are the alternative version which does not work.

[string]$secretString = "Secret message: The agent
was a man called Bond
007 BOND, James MI5 London
....... end"

# [string]$agent = '007 BOND'   # [regex]::Escape($agent)
[string]$result = $null

$secretString -match "(007 BOND[^\r\n]*)"
# $secretString -match "([regex]::Escape($agent)[^\r\n]*)"
$result = $Matches[0]

Write-Host "The full name of agent is: $result"

The output for working version is:

True
The full name of agent is: 007 BOND, James MI5 London

The output for non-working version (uncomment $agent declaration & swap $secretString -match line from explicit to escaped) is:

False
The full name of agent is: 007 BOND, James MI5 London

How can this happen? As I understand from Matching operators the $Matches automatic variable should be overwritten.

As it happens. If I open a new terminal in VS, to run the errant code again, I now get:

False
InvalidOperation:
    15 |  $result = $Matches[0]
         |  ~~~~~~~~~~~~~~~~~~~~~
         | Cannot index into a null array.

The messaging & logic is now consistent. This means I have two problems.

  1. What is wrong with my regex escape code?
  2. Why is the $Matches automatic variable not being overwritten? On the second run of the code it should be overwritten to null because the comparison operator match returns a false match.

Any suggestions would be appreciated.

Dave
  • 687
  • 7
  • 15
  • 4
    You are not concatenating strings. `"$([regex]::Escape($agent))[^\r\n]*"` or `[regex]::Escape($agent) + "[^\r\n]*"` will work. `$Matches` is only overwritten when the match is `True` (see [the docs](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-7.2#-match-and--notmatch)). – Wiktor Stribiżew Mar 10 '22 at 21:32
  • 1
    It's implied by Wiktor's comment, but you can find details on why `"([regex]::Escape($agent)[^\r\n]*)"` didn't work as you expected (lack of string interpolation) in [this answer](https://stackoverflow.com/a/71371267/45375). – mklement0 Mar 10 '22 at 21:51
  • @Wiktor Stribiżew Thank you. Yes. I need to be able to read these expressions accurately. I will be more careful next time. Your second example works and I believe is easier to read. Your first example gave me blank output. – Dave Mar 10 '22 at 22:13
  • 1
    @Dave, Wiktor's first example works too; verify with `$agent = 'does work'; "$([regex]::Escape($agent))[^\r\n]*"` – mklement0 Mar 11 '22 at 03:14
  • 1
    Yes. You are correct. It works for me now too. I don't know what I was doing there. – Dave Mar 11 '22 at 19:41

1 Answers1

3

As for the second point, check the note section here regarding matches:

When $Matches is populated in a session, it retains the matched value until it's overwritten by another match. If -match is used again and no match is found, it doesn't reset $Matches to $null. The previously matched value is kept in $Matches until another match is found.

Bardam
  • 56
  • 4
  • Thanks. Yes the notes section implies what you are saying. And the behavior I get certainly confirms this. But the last line of the same docs about_Comparison_operators does state "If there are no matches in a collection, the operators return an empty array." – Dave Mar 10 '22 at 22:10
  • 2
    @Dave, that quote refers to the case where the LHS is a _collection_ (array), in which case `-match` always acts as a _filter_ (returns the (potentially empty) subarray of matching elements rather than a Boolean) and _never_ populates `$Matches` – mklement0 Mar 11 '22 at 03:12