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

grm*_*mbl 2 regex powershell

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

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

$changelog = 'C:\Source\VSTS\AcmeLab\AcmeLab Core\changelog.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.

#>
Run Code Online (Sandbox Code Playgroud)

我需要的结果是:

v1.0.23
- Adds an IContainer API.
- Bugfixes.
Run Code Online (Sandbox Code Playgroud)

更新:

使用选项..

$changelog = 'C:\Source\VSTS\AcmeLab\AcmeLab Core\changelog.md'
$regex = '(?smi)([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'

Get-Content -Path $changelog -Raw | Select-String -Pattern $regex -AllMatches
Run Code Online (Sandbox Code Playgroud)

我也一无所获..(无论我使用\n\r\n

mkl*_*nt0 5

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

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

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

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

  • \r?\n 匹配 CRLF 和仅 LF 换行符。
  • 你可以做的正则表达式会更有效通过使(...)子表达式非捕获,因为你不是在它捕获感兴趣的是:(?:...)

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


至于你尝试什么

'([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'
Run Code Online (Sandbox Code Playgroud)

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

'(?smi)([Vv][0-9]+\.[0-9]+\.[0-9]+\n)(^-.*$\n)+'
Run Code Online (Sandbox Code Playgroud)

不能按预期工作,因为通过使用选项s(单行),您也.匹配了换行符,因此贪婪的子表达式(例如).*将匹配字符串的其余部分,跨行。结果,从第一个块开始的所有内容都匹配。


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