23

使用 Powershell,我知道如何使用正则表达式在文件中搜索复杂的字符串,并将其替换为某个固定值,如以下代码段所示:

Get-ChildItem  "*.txt" |
Foreach-Object {
    $c = ($_ | Get-Content)
    $c = $c -replace $regexA,'NewText'
    [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
}

现在我试图弄清楚如何替换正则表达式的每个匹配项的一个小节。这可以像上面那样在一个平稳的步骤中完成吗?或者您是否必须提取较大正则表达式的每个匹配项,在其中进行搜索和替换,然后以某种方式将该结果粘贴回原始文本?

举个例子来说明,假设在下面的测试文本中,我只想在下面的文本中找到像“TEST=*1404”这样编号为 14xx 的实例,并将 14xx 替换为 16xx?

A 2180 1830 12 0 3 3 TEST=C1404
A 900 1830 12 0 3 3 TEST=R1413
A 400 1830 12 0 3 3 TEST=R1411
A 1090 1970 12 0 3 3 TEST=U1400
A 1090 1970 12 0 3 3 TEST=CSA1400
A 1090 1970 12 0 3 3 TEST=CSA1414
A 1090 1970 12 0 3 3 TEST=CSA140
A 1090 1970 12 0 3 3 TEST=CSA14001
A 1090 1970 12 0 3 3 TEST=CSA17001

即我希望生成的文本如下所示,您会注意到只有前 6 行应该更改:

A 2180 1830 12 0 3 3 TEST=C1604
A 900 1830 12 0 3 3 TEST=R1613
A 400 1830 12 0 3 3 TEST=R1611
A 1090 1970 12 0 3 3 TEST=U1600
A 1090 1970 12 0 3 3 TEST=CSA1600
A 1090 1970 12 0 3 3 TEST=CSA1614 <- Second instance of '14' shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA140 <- Shorter numbers shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA14001 <- Longer numbers shouldn't change
A 1090 1970 12 0 3 3 TEST=CSA17001

以下正则表达式似乎可以找到我需要替换的较大字符串,但我不知道 Powershell ( replace?) 中的哪些功能可用于替换结果的子字符串。另外,如果有帮助,请随时提出更好的正则表达式。

$regexA = "\bTEST=\b[A-Za-z]+14\d\d\r"

我宁愿不必硬编码可能出现在“=”和数字之间的内容的详尽列表,例如“R”、“C”、“CSA”等。

我已经做了一个小时左右的工作,在那里我得到了正则表达式的所有匹配项,在其中搜索以将 14 替换为 16,然后用旧值和新值对原始文本运行替换,例如replace($myText,"TEST=CSA1400","TEST=CSA1600"),但这是没有很好地掩盖特殊情况,感觉就像我正在走向兔子洞。

4

3 回答 3

32

您需要对要保留的子表达式进行分组(即将它们放在括号之间),然后通过变量$1$2替换字符串引用这些组。尝试这样的事情:

$regexA = '( TEST=[A-Za-z]+)14(\d\d)$'

Get-ChildItem '*.txt' | ForEach-Object {
    $c = (Get-Content $_.FullName) -replace $regexA, '${1}16$2' -join "`r`n"
    [IO.File]::WriteAllText($_.FullName, $c)
}
于 2013-11-11T22:30:14.223 回答
3

这是一个使用脚本块委托(有时称为评估器)的示例:

$regex = [regex]'( TEST=\D+)14(\d{2})\s*$'
$evaluator = { '{0}16{1}' -f $args[0].Groups[1..2] }
filter set-number { $regex.Replace($_, $evaluator) }

foreach ($file in Get-ChildItem  "*.txt")
 {
   ($file | get-content) | set-number | Set-Content $file.FullName
 }

它可以说比 -replace 运算符更复杂,但允许您使用 powershell 运算符来构造替换文本,因此您可以执行任何可以放入脚本块的操作。

于 2013-11-12T04:28:03.033 回答
2

试试这个:

Get-ChildItem  "*.txt" |
Foreach-Object {
  $c = $_ | Get-Content | Foreach {$_ -replace '(?<=TEST=\D+)14(?=\d{2}(\D+|$))','16'}
  $c | Out-File $_.FullName -Enc Ascii
}
于 2013-11-11T22:37:53.787 回答