powershell 2 与 powershell 5 行尾锚点的 powershell 正则表达式问题

powershell regex issue with powershell 2 vs. powershell 5 end of line anchor

给定以下代码:

$inputString = "`r`n#cmakedefine BREAK_THE_CODE`r`n"
$match = '(?m)^(.*?)#cmakedefine(.*?)$'
$replace = 'hello #undef goodbye '
$retVal = $inputString -replace $match,$replace -join "`r`n"
Write-Host $retVal

Powershell 5 产生以下(预期)输出:

hello #undef BREAK_THE_CODE goodbye 

Powershell 2 产生以下(意外)输出:

 goodbye def BREAK_THE_CODE

有人知道为什么吗?或者有一个解决方法。如果 [regex::] 能给我带来更多的一致性,我可以接受。我需要两个版本才能产生相同的结果。对于它的价值,你好和再见最终将成为 /**/ 但我试图避免将问题与任何可以解释为特殊字符的东西混淆。

编辑:马特在下面的回答详细说明了两个 Powershell 版本都产生相同的输出,[CR][LF]hello #undef BREAK_THE_CODE[CR] goodbye [LF] 版本之间的明显区别实际上是 ISE 与非 ISE 和 Write-Host。所以根本问题是我的正则表达式刚刚被破坏,虽然我仍然不知道为什么会这样。

我最终得到:

$match = "(?m)^(.*?)#cmakedefine([^\r\n]*)"
$replace = '/* #undef */'

作为一个小边栏,VS 2015 IDE(几乎肯定使用相同的正则表达式引擎)的帮助将 \r?$ 列为正确的行尾锚点: https://msdn.microsoft.com/en-us/library/2k3te2cs.aspx

可以通过捕获它的 \r 部分来使锚点工作,我最初是这样做的,但我更喜欢下面的 Wiktor 解决方案。

这与正则表达式或 PS 版本没有任何关系,但与 Write-Host 如何处理 中间那辆孤独的马车 return字符串。我也可以在 PowerShell 2.0 和 5.0 中重现这一点,但 不是 ISE,因为它是一个不同的环境。您可以将您的发现缩减为该语句。

write-host "Hello Matt`rBagel"

它应该打印 "Hello Matt Bagel" 而不是打印 "Bagel Matt" 回车 return 重置主机光标位置然后继续输入。所以它确实打印了 Hello Matt,但随后用 "Bagel" 覆盖了 "Hello"。

Wikipedias definition of CR 将有助于解释当控制字符单独存在时这是设计状态。

A carriage return, sometimes known as a cartridge return and often shortened to CR, or return, is a control character or mechanism used to reset a device's position to the beginning of a line of text.

如果您只在命令行上使用 Write-Output$retVal,您将看不到它。删除单独的 CR 也可以解决此问题。

write-host ("Hello Matt`rBagel" -replace "`r(?<!`n)")

您遇到此问题的原因是您的 (.*?)$ 似乎锚定在 "`n" 上,因此捕获组正在消耗运输 return。如果这是您在真实数据中看到的情况,那么您需要以某种方式对其进行解释。

您的 '(?m)^(.*?)#cmakedefine(.*?)$' 模式的问题是 . 符号匹配除 LF(仅换行符)以外的任何字符,并且 (?m) 修饰符使 $锚点匹配就在 LF 之前,在可能的 CR 之后。这意味着,CR 符号出现在捕获组 2 的末尾。

看看你的字符串:

<CR><LF>
#cmakedefine BREAK_THE_CODE<CR><LF>
|------------- MATCH ---------|
||          |-----Group2------|

第 1 组值为空,第 2 组包含 BREAK_THE_CODE。因此,CR 变为 "lonely" 为

这是一个可能的修复方法,用 [^\r\n]* 替换最后一个惰性点模式,匹配除 CR 和 LF 之外的 0 个或更多字符(然后 $ 变得多余):

$match = '(?m)^(.*?)#cmakedefine([^\r\n]*)'
$replace = 'hello #undef goodbye '

这是一个 regex demo(不幸的是,table 中的所有值都从空格中删除了,但它现在应该可以正常工作了。)