Powershell 正则表达式 gis 标志支持

Powershell regex gis flags support

我想在使用 gis 标志的 Powershell 中使用这个正则表达式,

https://regex101.com/r/yoM4cV/1

/(?<=#start)(.+)(?=#end)/gis

匹配#start 和#end 之间的句子

  #start
  hello powershell regex
  what is the equivalent of flags gis
  #end

我找不到任何关于 Powershell 的 gis 标志支持的信息。 Powershell 中缺少这个吗?如果是,还有什么选择?

更新:我问是因为这个 returns false

  $test=@'
  #start
  hello powershell regex
  what is the equivalent of flags gis
  #end
  '@

  $test -match (?<=#start)(.+)(?=#end)

PowerShell 中的正则表达式是用字符串文字定义的,而不是正则表达式文字(类似于 action/pattern/flags 的结构)。

g 标志在 PowerShell 中未作为正则表达式选项实现,您需要使用多重匹配。如果您使用 Select-String,您将需要 -AllMatches 选项来匹配所有匹配项。如果您使用 .NET 正则表达式 API,ypu 可以使用 Regex.Matches 方法查找所有匹配项。

is 标志使用更简单,您可以将它们用作内联修饰符,(?s)(?i),或连接为 (?si),您可以将它们放在图案的开头,以便它们可以影响整个图案(或将它们放在图案中的任何位置,以便影响它们右侧的所有图案(并且您可以使用 [=23= 禁用它们]/(?-i)/(?-si))).

如果定义正则表达式对象,可以使用[Text.RegularExpressions.RegexOptions]'Singleline'[Text.RegularExpressions.RegexOptions]'IgnoreCase'[Text.RegularExpressions.RegexOptions]'IgnoreCase, Singleline'.

当您需要使用 s 标志时,您必须确保您的输入被视为单个多行字符串。如果你读入文件,你需要确保你使用 -Raw 选项和 Get-Content.

这是 PowerShell 中 gis 标志“转换”的示例:

$rx = [System.Text.RegularExpressions.Regex]::new('(?<=#start)(.*?)(?=#end)', [Text.RegularExpressions.RegexOptions]'IgnoreCase, Singleline')
$test=@'
   #start
   hello powershell regex
   what is the equivalent of flags gis
   #end
'@
$rx.Matches($test).value

输出:

  hello powershell regex
  what is the equivalent of flags gis

可以获得相同的结果
($test | Select-String -Pattern '(?si)(?<=#start)(.*?)(?=#end)' -AllMatches).Matches.Value

要修正你的例子,你需要这样写:

$test -match '(?s)(?<=#start)(.+)(?=#end)'
  • 启用 single-line 模式 (?s) 以允许 . 匹配多行。
  • 引用正则表达式,因为 () 是 PowerShell 分组运算符,在您的示例中,它使 PowerShell 尝试将正则表达式模式解释为 PowerShell 表达式,但这是行不通的。相反,将其作为文字字符串传递给 -match.

详细解释:

gis开始,只有icase-insensitive)和ssingle-line) 在 PowerShell 中作为标志可用(或更普遍地在 .NET 中,因为 PowerShell 在底层使用 .NET RegEx 支持)。

您可以在模式的开头将这些指定为 inline flags ...

(?is)(?<=#start)(.+)(?=#end)

... 或使用 Regex class, which accepts a RegExOptions 参数的 options 参数:

$options = [System.Text.RegularExpressions.RegexOptions] 'IgnoreCase, Singleline'
[Regex]::Match('text', 'pattern', $options)

g全局)标志不能直接使用。您可以通过调用 [Regex]::Matches() method, which finds all matches (contrary to [Regex]::Match() 和仅找到第一个匹配项的 -match 运算符来有效地使用它)。它的输出是已找到的所有匹配项的集合。

或者,您可以使用带有参数 -AllMatchesSelect-String,如 所示。

出于演示目的,我稍微修改了您的示例,以便它实际上找到了多个匹配项(您的原始 RegEx 匹配第一个 #start 到最后一个 #end 之间的所有内容,因此它只会找到一个匹配项).

$text = @'
#start
hello powershell regex
what is the equivalent of flags gis
#end
#start
foobar
#end
'@

$pattern = '(?is)(?<=#start)(.+?)(?=#end)'

foreach( $match in [Regex]::Matches($text, $pattern) ) {
    '----- Match -----'
    $match.Groups[1].Value   # Output the captured value of the 1st group
}

输出:

----- Match -----

hello powershell regex
what is the equivalent of flags gis

----- Match -----

foobar