如何在正则表达式中使用非捕获组,即(?:),它们有什么好处?


当前回答

我想我会给你答案。在未检查匹配是否成功的情况下,不要使用捕获变量。

除非匹配成功,否则捕获变量$1等无效,并且它们也不会被清除。

#!/usr/bin/perl  
use warnings;
use strict;   
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
    print "Fred wants a  $1";
}
else
{
    print "Fred dont wants a $1 $2";
}

在上面的示例中,为了避免在$1中捕获bronto,使用了(?:)。

如果模式匹配,则$1被捕获为下一个分组模式。

因此,输出如下:

Fred wants a burger

如果不希望保存匹配项,则此选项很有用。

其他回答

历史动机:

非捕获组的存在可以用括号来解释。

考虑表达式(a|b)c和a|bc,由于串联优先于|,这些表达式分别表示两种不同的语言({ac,bc}和{a,bc})。

然而,括号也用作匹配组(如其他答案所解释的…)。

当您想有括号但不想捕获子表达式时,可以使用NON-CAPTURING GROUPS。在示例中,(?:a|b)c

它非常简单,我们可以通过简单的日期示例来理解,假设日期被提到为2019年1月1日或2019年5月2日或任何其他日期,并且我们只想将其转换为dd/mm/yyyy格式,那么我们不需要月份的名称,即1月或2月,因此为了捕获数字部分,而不是(可选)后缀,您可以使用非捕获组。

所以正则表达式将是,

([0-9]+)(?:January|February)?

就这么简单。

?: 当您想对表达式进行分组,但不想将其保存为字符串的匹配/捕获部分时,使用。

一个例子是匹配IP地址:

/(?:\d{1,3}\.){3}\d{1,3}/

请注意,我不在乎保存前3个八位字节,但(?:…)分组允许我缩短正则表达式,而不会导致捕获和存储匹配项的开销。

我想我会给你答案。在未检查匹配是否成功的情况下,不要使用捕获变量。

除非匹配成功,否则捕获变量$1等无效,并且它们也不会被清除。

#!/usr/bin/perl  
use warnings;
use strict;   
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
    print "Fred wants a  $1";
}
else
{
    print "Fred dont wants a $1 $2";
}

在上面的示例中,为了避免在$1中捕获bronto,使用了(?:)。

如果模式匹配,则$1被捕获为下一个分组模式。

因此,输出如下:

Fred wants a burger

如果不希望保存匹配项,则此选项很有用。

我不能评论最上面的答案来这样说:我想补充一个明确的观点,这只是在最上面的回答中暗示的:

非捕获组(?…)不会从原始完全匹配中删除任何字符,它只会对程序员进行可视化的正则表达式重组。

要访问正则表达式的特定部分而不定义外来字符,您将始终需要使用.group(<index>)