Regular Expressions are a -replace’s best friend

by Don Jones


Are you familiar with PowerShell’s -replace operator?

"John Jones" -replace "Jones","Smith"

Most folks are aware of it, and rely on it for straightforward string replacements like this one. But not very many people know that -replace also does some amazing stuff using regular expressions.

"192.168.15.12,192.168.22.8" -replace "\.\d{2}\.","10"

That’d change the input string to “192.168.10.12,192.168.10.8,” replacing all occurrences of two digits, between periods, to 10. The 12 would be skipped because it isn’t followed by a period, as specified in the pattern. Note that all occurrences are replaced, in keeping with the usual operation of -replace.

The operator can also do capturing expressions, and this is where it gets really neat-o.

"Don Jones" -replace "([a-z]+)\s([a-z]+)",'$2, $1'

Here, I’ve specified two capturing expressions in parentheses, with a space character between them. PowerShell will capture the first to $1, and the second to $2. Those aren’t actually variables, which is important. In my replacement string, I put $2 first, followed by a comma, a space, and $1. The resulting string will be “Jones, Don”. It’s important that my replacement string be in single quotes. In double quotes, the shell will try and treat $1 and $2 as variables, instead of using them as captured regex placeholders. I kinda wish they’d used something other than a $ for the captured placeholders, so that they didn’t look like variables, but the syntax is in keeping with regex standards.

I think it’s cool to see all the places a regex can be put to use. The -split operator also supports regex syntax as a way of specifying the separator that will be used to break a string into components, so you’re not limited to splitting just on a single character like a comma.

Apart from the well-known -match operator and the Select-String command, where else have you used a regex in PowerShell?

4 thoughts on “Regular Expressions are a -replace’s best friend

  1. Barry Thomson

    Hi,

    I’m trying to use this to change the output of the line below from Computername\Username, to simply Username
    Get-wmiobject win32_computersystem | select username

    When I use the code below, the output is @{username=\Username}

    $User= get-wmiobject win32_computersystem -computer $ComputerName2.text | select username
    $ID= $User-replace “Computername”, “”

    Where am I going wrong on this one?

    Thanks

    1. Ken Row

      Part of the problem is that $user, when presented to -replace, is wrapped by “@{” and “}”.

      Another part of the problem is that you didn’t include the “\” in your search pattern.

      One way to approach this would be to first eliminate everything up to the \, then do another replace to eliminate the }:

      $id=$user -replace "^.*\\", "" -replace "}", ""

      In my version of Powershell, I don’t seem to have the ability to use capturing expressions, as referenced in the above article. If I did, I could get by with just one -replace (note: I’ve not tried this as I don’t have capturing expressions):

      $id=$user -replace "^.*\\(.*\)}$", "$1"

  2. Dave Wyatt

    On a side note, this operation:

    “192.168.15.12,192.168.22.8” -replace “\.\d{2}\.”,”10″

    doesn’t just change the numbers, it also removes the periods. You’d need to use “.10.” as the replace string to make sure they remained, or use lookahead / lookbehind assertions in the pattern so the periods were checked, but weren’t actually part of the match:

    “192.168.15.12,192.168.22.8” -replace “\.\d{2}\.”,”.10.”

    “192.168.15.12,192.168.22.8” -replace “(?<=\.)\d{2}(?=\.)","10"

    Just putting the periods in the replace string is easier to read, in this case, but the lookahead / lookbehind assertions can be useful for some tricky problems.

Leave a Reply