Powershell 中的正则表达式无法检查换行符



我正在尝试获取发行说明的第一个块...
(请参阅代码中的示例内容(

每当我使用简单的东西时,它都可以工作,
只有当我尝试 跨多行搜索 (n(。
我正在使用(Get-Content $changelog | Out-String)因为它返回 1 个字符串而不是每行的数组。

$changelog = 'C:SourceVSTSAcmeLabAcmeLab Corechangelog.md'
$regex = '([Vv][0-9]+.[0-9]+.[0-9]+n)(^-.*$n)+'
(Get-Content $changelog | Out-String) | Select-String -Pattern $regex -AllMatches
<#
SAMPLE:
------
v1.0.23
- Adds an IContainer API.
- Bugfixes.
v1.0.22
- Hotfix: Language operators.
v1.0.21
- Support duplicate query parameters.
v1.0.20
- Splitting up the ICommand interface.
- Fixing the referrer header empty field value.
#>

我需要的结果是:

v1.0.23
- Adds an IContainer API.
- Bugfixes.

更新:

使用选项..

$changelog = 'C:SourceVSTSAcmeLabAcmeLab Corechangelog.md'
$regex = '(?smi)([Vv][0-9]+.[0-9]+.[0-9]+n)(^-.*$n)+'
Get-Content -Path $changelog -Raw | Select-String -Pattern $regex -AllMatches

我也一无所获..(无论我使用n还是rn(

  • 除非你坚持使用 PowerShell v2,否则使用Get-Content -Raw将整个文件作为单个字符串读取会更简单、更高效;此外,Out-String会为字符串添加一个额外的换行符。[1]
  • 由于您只查找第一个匹配项,因此您可以使用-match运算符 - 无需Select-String-AllMatches开关。
    • 注意:虽然您可以在没有它的情况下使用Select-String,但使用-match运算符更有效,因为您已经将整个文件读入内存。
  • 默认情况下,正则表达式匹配在 PowerShell 中始终不区分大小写,与 PowerShell 的整体不区分大小写一致。

因此,以下内容返回第一个块(如果有(:

if ((Get-Content -Raw $changelog) -match '(?m)^vd+.d+.d+.*(r?n-s?.*)+') { 
# Match found - output it.
$Matches[0] 
}

*(?m)打开内联正则表达式选项m(多行(,这会导致锚点^$匹配单个行的开头和结尾,而不是整个字符串的开头和结尾。

  • r?n匹配 CRLF 和仅 LF 换行符。
  • 您可以通过使(...)子表达式不捕获来使正则表达式稍微更有效率,因为您对它捕获的内容不感兴趣:(?:...).

请注意,-match本身返回一个布尔值(带有标量 LHS(,但有关匹配的信息记录在自动$Matches哈希表变量中,其0条目包含整体匹配。


至于你尝试过的

'([Vv][0-9]+.[0-9]+.[0-9]+n)(^-.*$n)+'

不起作用,因为默认情况下$只匹配输入字符串的最后,最后一行的末尾(尽管可能在最后一个换行符之前(。 要使$匹配每行的末尾,您必须打开多行正则表达式选项(您在第二次尝试中所做的(。 结果,没有什么比拟的了。

'(?smi)([Vv][0-9]+.[0-9]+.[0-9]+n)(^-.*$n)+'

无法按预期工作,因为通过使用选项s(单行(,您.换行符匹配,以便贪婪的子表达式(如.*(将跨行匹配字符串的其余部分。 结果,从比赛的第一个块开始的一切。


[1] GitHub 问题 #14444 中讨论了这种有问题的行为。