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 中的所有值都从空格中删除了,但它现在应该可以正常工作了。)
给定以下代码:
$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 中的所有值都从空格中删除了,但它现在应该可以正常工作了。)