首页 > 解决方案 > Powershell正则表达式替换两个相同字符之间的特定字符

问题描述

我正在尝试使用 Powershell 用分号分隔的文件中;的管道替换分号|,因此它是出现在双引号之间的一组特定分号"。这是文件的示例,具体部分以粗体显示:

营地;巴西;AI;BCS GRU;;MIL-32011257;172-43333640;; "1975995;1972871;1975" ;FAC0088/21;3;20.000;24.8;25.000;.149;眼镜备件,;EXW;C;.00;EUR;

我试过使用-replace,如下:

(Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace '".*(;).*"',"|" } |

但是,正则表达式不会用管道替换引号之间的分号。我尝试了其他几个正则表达式无济于事。我会怎么做才能做到这一点?

标签: regexpowershell

解决方案


您可以使用Regex.Replace带有回调的方法作为替换参数:

$s = 'Camp;Brazil;AI;BCS GRU;;MIL-32011257;172-43333640;;"1975995;1972871;1975";FAC0088/21;3;20.000;24.8;25.000;.149;GLASSES SPARE PARTS,;EXW;C;.00;EUR;'
$rx = [regex]'"[^"]*"'
$rx.Replace($s, { param($m) $m.value.Replace(';','|') })
# => Camp;Brazil;AI;BCS GRU;;MIL-32011257;172-43333640;;"1975995|1972871|1975";FAC0088/21;3;20.000;24.8;25.000;.149;GLASSES SPARE PARTS,;EXW;C;.00;EUR;

也就是说,匹配两个"字符之间的任何子字符串,并仅将所有;字符替换|为匹配项中的字符。

此外,这里是 PowerShell Core v6.1+ 版本,您可以在其中传递一个脚本块作为-replace替换操作数,其中匹配表示为自动$_变量:

(Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace '"[^"]*"', { $_.Value.Replace(';', '|') } }

为什么不使用环视?

由于左右分隔符是相同的单个字符, ",因此任何基于环视的解决方案都将是错误的或太长并且仍然容易出错。之所以会发生这种情况,是因为环视不会消耗它们匹配的文本,"因此每个文本都可以作为初始的". 看一下(?<="[^"]*);(?=[^"]*") 正则表达式,其中"b;c;d";1;23;"45;677777;z"变成了,"b|c|d"|1|23|"45|677777|z"因为;1and2323and"之间找到了两个双引号。

类似的问题也存在于\G基于 - 的模式上,该模式可用于匹配两个不同分隔符之间的多个匹配项,并且通常不用于 .NET 正则表达式,因为后者支持无限宽度的lookbehinds。


推荐阅读