simplicITy
simplicITy

Reputation: 101

Can PowerShell replace a case sensitive portion of text it found using -clike?

Let's say I have two addresses:

I need to update the directional portion from Ne to NE. However, I don't want to update Newark to NEwark and the same for Netherland. I think I can find all the instances easy enough with this IF statement in a loop:

$testAddress = '123 Newark Road Ne'
if (($testAddress -clike '* Ne') -or ($testAddress -clike '* Ne *')){
   #code to replace Ne
}

But how do I go about replacing it? I can't use a -creplace '* Ne', '* NE'. Finding the index of '* Ne' just gives me -1 so I don't think I can do anything with that. I'm sure there's an easy concept that I'm just not coming across.

Upvotes: 1

Views: 347

Answers (3)

swbbl
swbbl

Reputation: 864

You can use Regular Expressions to replace a certain part of your input with something which is not possible in the substitution operand in a regex expression by design (like uppercasing in .NET) by using a MatchEvaluator, which is constructed in PowerShell like a scriptblock.

With that MatchEvaluator you can manipulate the matched part like you want, hence you are not restricted to anything when it comes to manipulation.

Beginning with PowerShell 6 you can even use it directly with the -replace and -creplace operators.
PowerShell versions below 6 does not have this option, but it's still possible using the .NET Regex Replace Method [regex]::Replace() with a MatchEvaluator.

PS 5.1

$textToReplace = 'Ne 123 Newark Road Ne', '123 Newark Road Ne', '987 Ne Netherland Avenue'

foreach ($text in $textToReplace) {
    # using a scriptblock as System.Text.RegularExpressions.MatchEvaluator
    # the param() part is mandatory. Everything that follows is the return for that particular match
    [regex]::Replace($text, '(?<!\w)Ne(?!\w)', { param($regexMatch) $regexMatch.Value.ToUpper() })
}

PS 6+

$textToReplace = 'Ne 123 Newark Road Ne', '123 Newark Road Ne', '987 Ne Netherland Avenue'

foreach ($text in $textToReplace) {
    $text -creplace '(?<!\w)Ne(?!\w)', { $_.Value.toUpper() }
}

Regular Expression Pattern Explanation

The pattern (?<!\w)Ne(?!\w) matches all words Ne for which the preceding and following character is not a word character using a negative lookbehind (?<!) and negative lookahead (?!) group construct.

\w (Word) in .NET includes all Unicode characters of the following categories:
MSFT: Character classes in regular expressions -> Word character: \w:

These include, but are not limited to:

  • a-z and variants like è
  • A-Z and variants like À
  • 0-9
  • _
  • cyrillic characters
  • chinese characters
  • ...

In short, \w captures almost all word characters which are represented in the Unicode character set.

Resources

MSFT: Replacement with a script block in PS6+

Upvotes: 6

Theo
Theo

Reputation: 61068

Or use word boundaries around Ne:

'123 Newark Road Ne','987 Ne Netherland Avenue' | ForEach-Object {
    if ($_ -cmatch '(\bNe\b)') { $_ -creplace '(\bNe\b)', $Matches[1].ToUpper() }
    else { $_ }
}

Output

123 Newark Road NE
987 NE Netherland Avenue

Upvotes: 0

Santiago Squarzon
Santiago Squarzon

Reputation: 60025

@('123 Newark Road Ne'
'987 Ne Netherland Avenue')|foreach{
    switch -regex ($_)
    {
        'Ne$'{$_ -replace 'Ne$','NE'}
        ' Ne '{$_ -replace ' Ne ',' NE '}
        Default {$_}
    }
}

Upvotes: 0

Related Questions