PowerShell 可以替换使用 -clike 找到的文本中区分大小写的部分吗?

问题描述

假设我有两个地址:

  • 纽瓦克路 123 号
  • 荷兰大道 987 号

我需要将方向部分从 Ne 更新到 NE。但是,我不想将纽瓦克更新为 NEwark,而对于荷兰也是如此。我想我可以通过循环中的这个 IF 语句轻松找到所有实例:

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

但是我该如何更换它呢?我不能使用 -creplace '* Ne','* NE'。找到 '* Ne' 的索引只会给我 -1,所以我认为我不能用它做任何事情。我敢肯定有一个简单的概念,我只是没有遇到过。

解决方法

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

使用 MatchEvaluator,您可以随意操作匹配的部分,因此在操作方面您不受任何限制。

从 PowerShell 6 开始,您甚至可以直接将其与 -replace-creplace 运算符一起使用。
低于 6 的 PowerShell 版本没有此选项,但仍然可以使用 .NET Regex Replace Method [regex]::Replace() 和 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','987 Ne Netherland Avenue'

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

正则表达式模式说明

模式 (?<!\w)Ne(?!\w) 匹配所有使用 Nenegative 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+

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

或者在 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