Search code examples
regexpowershelltext

Negative Lookbehind Works in Editor But Not in Powershell Script


Using the following. I am attempting to replace spaces with comma-space for all instances in a string. While avoiding repeating commas already present in the string.

Test string:

'186 ATKINS, Cindy Maria 25 Every Street Smalltown, Student'

Using the following code:

Get-Content -Path $filePath | 
ForEach-Object {   
$match = ($_ | Select-String $regexPlus).Matches.Value
$c = ($_ | Get-Content)
    $c = $c -replace $match,', '    
    $c
}

The output is:

'186, ATKINS,, Cindy, Maria, 25, Every, Street, Smalltown,, Student'

My $regexPlus value is:

$regexPlus = '(?s)(?<!,)\s'

I have tested the negative lookbehind assertion in my editor and it works. Why does it not work in this Powershell script? The regex 101 online editor produces this curious mention of case sensitivity:

Negative Lookbehind (?<!,)
Assert that the Regex below does not match
 
, matches the character , with index 4410 (2C16 or 548) literally (case sensitive)

I have tried editing to:

$match = ($_ | Select-String $regexPlus -CaseSensitive).Matches.Value

But still not working. Any ideas are welcome.


Solution

  • Part of the problem here is that you are trying to force through the regex to do the replacement, when, like @WiktorStribiżew mentions, simply use -replace like it's supposed to be used. i.e. -replace does all the hard work for you.

    When you do this:

    $match = ($_ | Select-String $regexPlus).Matches.Value
    

    You are right, you are trying to find Regex matches. Congratulations! It found a space character, but when you do this:

    $c = $c -replace $match,', '
    

    It interprets $match as a space character like this:

    $c = $c -replace ' ',', ' 
    

    And not as a regular expression that you might have been expecting. That's why it's not seeing the negative lookbehind for the commas, because all it is searching for are spaces, and it is dutifully replacing all the spaces with comma spaces.

    The solution is simple in that, all you have to do is simply use the Regex text in the -replace string:

    $regexPlus = '(?s)(?<!,)\s'
    $c = $c -replace $regexPlus,', '
    

    e.g. The negative lookbehind working as advertised:

    PS C:> $str = '186 ATKINS, Cindy Maria 25 Every Street Smalltown, Student'
    PS C:> $regexPlus = '(?s)(?<!,)\s'
    PS C:> $str -replace $regexPlus,', '
    186, ATKINS, Cindy, Maria, 25, Every, Street, Smalltown, Student