PowerShell 能否替换它使用 -clike 找到的区分大小写的文本部分?

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

假设我有两个地址:

我需要将方向部分从 Ne 更新为 NE。但是,我不想将 Newark 更新为 NEwark,也不想将 Netherland 更新为 NEwark。我想我可以在一个循环中使用这个 IF 语句很容易地找到所有实例:

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

但是我该如何更换它呢?我不能使用 -creplace '* Ne', '* NE'。找到 '* Ne' 的索引只会给我 -1,所以我认为我对此无能为力。我确定有一个简单的概念我只是没有遇到。

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

您可以使用正则表达式,通过使用 MatchEvaluator,将输入的特定部分替换为在正则表达式中的替换操作数中不可能设计的内容(如 .NET 中的大写),它像脚本块一样在 PowerShell 中构建。

有了 MatchEvaluator,您可以随心所欲地操作匹配的部分,因此在操作方面您不受任何限制。

从 PowerShell 6 开始,您甚至可以直接将其与 -replace-creplace 运算符一起使用。
低于 6 的 PowerShell 版本没有此选项,但仍然可以使用带有 MatchEvaluator 的 .NET 正则表达式替换方法 [regex]::Replace()

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() })
}

PS6+

$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() }
}

正则表达式模式解释

模式 (?<!\w)Ne(?!\w) 匹配所有单词 Ne,其前后字符不是使用 negative lookbehind (?<!)negative lookahead (?!) 组构造的单词字符。

\w .NET 中的 (Word) 包括以下类别的所有 Unicode 字符:
MSFT: Character classes in regular expressions -> Word character: \w:

包括但不限于:

  • a-zè
  • 等变体
  • A-ZÀ
  • 等变体
  • 0-9
  • _
  • 西里尔字符
  • 汉字
  • ...

简而言之,\w捕获几乎所有在Unicode字符集中表示的单词字符。

资源

MSFT: Replacement with a script block in PS6+

或者在Ne周围使用单词边界:

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

输出

123 Newark Road NE
987 NE Netherland Avenue