什么是非捕获组? 问号跟一个冒号(?:)是什么意思?

读了一些教程后,我仍然不明白。

有人可以解释一下?:是用来做什么的?

让我试着用一个例子来解释这一点。

考虑以下文字:

 https://stackoverflow.com/ https://stackoverflow.com/questions/tagged/regex 

现在,如果我使用下面的正则expression式…

 (https?|ftp)://([^/\r\n]+)(/[^\r\n]*)? 

…我会得到以下结果:

 Match "https://stackoverflow.com/" Group 1: "http" Group 2: "stackoverflow.com" Group 3: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "http" Group 2: "stackoverflow.com" Group 3: "/questions/tagged/regex" 

但我不关心协议 – 我只想要URL的主机和path。 所以,我改变正则expression式包括非捕获组(?:)

 (?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)? 

现在,我的结果如下所示:

 Match "https://stackoverflow.com/" Group 1: "stackoverflow.com" Group 2: "/" Match "https://stackoverflow.com/questions/tagged/regex" Group 1: "stackoverflow.com" Group 2: "/questions/tagged/regex" 

看到? 第一组还没有被抓获。 parsing器使用它来匹配文本,但是在最后的结果中忽略它。


编辑:

按照要求,让我试着解释一下小组。

那么,群体有很多目的。 他们可以帮助你从一个更大的匹配(也可以命名)提取确切的信息,他们让你重新匹配一个以前的匹配组,并可以用于替代。 我们来看一些例子吧?

好吧,想象一下你有一些XML或HTML(请注意, 正则expression式可能不是最好的工具 ,但作为一个例子很好)。 你想分析标签,所以你可以做这样的事情(我已经添加了空间,使其更容易理解):

  \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\> or \<(.+?)\> [^<]*? \</\1\> 

第一个正则expression式有一个命名组(TAG),而第二个则使用一个公共组。 两个正则expression式都做同样的事情:它们使用第一组中的值(标签的名称)来匹配结束标签。 区别在于第一个使用名称来匹配值,第二个使用组索引(从1开始)。

我们现在尝试一些replace。 考虑以下文字:

 Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas. 

现在,让我们使用这个愚蠢的正则expression式:

 \b(\S)(\S)(\S)(\S*)\b 

这个正则expression式匹配至less3个字符的单词,并使用组来分隔前三个字母。 结果是这样的:

 Match "Lorem" Group 1: "L" Group 2: "o" Group 3: "r" Group 4: "em" Match "ipsum" Group 1: "i" Group 2: "p" Group 3: "s" Group 4: "um" ... Match "consectetuer" Group 1: "c" Group 2: "o" Group 3: "n" Group 4: "sectetuer" ... 

所以,如果我们应用替代string…

 $1_$3$2_$4 

…在它上面,我们试图使用第一组,添加一个下划线,使用第三组,然后第二组,添加另一个下划线,然后第四组。 结果string将如下所示。

 L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas. 

您也可以使用命名组进行replace,使用${name}

要使用正则expression式,我推荐http://regex101.com/ ,它提供了正则expression式工作的详细信息。 它也提供了几个正则expression式引擎可供select。

您可以使用捕获组来组织和分析expression式。 一个非捕获组有第一个好处,但没有第二个开销。 例如,您仍然可以说非捕获组是可选的。

假设你想匹配数字文本,但是一些数字可以写成第一,第二,第三,第四,…如果你想捕获数字部分,但不是(可选的)后缀,你可以使用非捕获组。

 ([0-9]+)(?:st|nd|rd|th)? 

这将匹配forms1,2,3,或forms1,2,3,…的forms,但它只会捕获数字部分。

?:在您想要对expression式进行分组时使用,但不希望将其另存为string的匹配/捕获部分。

一个例子可能是匹配一个IP地址的东西:

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

请注意,我不关心保存前3个八位字节,但(?:...)分组允许我缩短正则expression式,而不会招致捕获和存储匹配的开销。

它使得该组不捕获,这意味着该组匹配的子串不会被包含在捕获列表中。 用ruby来说明不同之处:

 "abc".match(/(.)(.)./).captures #=> ["a","b"] "abc".match(/(?:.)(.)./).captures #=> ["b"] 

捕获你的组可以在正则expression式中用来匹配, 或者你可以在正则expression式的replace部分使用它们。 制造一个非捕获组只是简单地免除了由于这些原因而使用该组。

如果你想捕捉许多不同的东西,并且有一些你不想捕捉的组,那么非捕获组是非常棒的。

这就是他们存在的原因。 在你学习团体的同时,学习primefaces团 ,他们做了很多! 也有环视群体,但他们有点复杂,并没有太多的使用。

在正则expression式中使用的例子(反向引用):

<([AZ][A-Z0-9]*)\b[^>]*>.*?</\1> [find一个xml标签(不支持ns)]

([AZ][A-Z0-9]*)是一个捕获组(在这种情况下,它是标记名)

之后在正则expression式中是\1 ,这意味着它只会匹配第一组中相同的文本([AZ][A-Z0-9]*)组)(在这种情况下,它匹配的是结束标签)。

历史的动机:非捕获群体的存在可以用括号来解释。 考虑expression式(a | b)c和a | bc,由于连接优先于|,这些expression式分别表示两种不同的语言({ac,bc}和{a,bc})。 然而,括号也被用作匹配组(正如其他答案所解释的那样)。

当你想有括号但不捕获子expression式你使用非捕获组。 在这个例子中,(?:a | b)c

让我试试这个例子:

正则expression式代码: – (?:animal)(?:=)(\w+)(,)\1\2

searchstring: –

第一行 – 动物=猫,狗,猫,老虎,狗

第二行 – 动物=猫,猫,狗,狗,老虎

第3行 – 动物=狗,狗,猫,猫,老虎

(?:animal) – >未捕获组1

(?:=) – >未捕获组2

(\w+) – >捕获组1

(,) – >捕获组2

\1 – >捕获组1的结果,即1号线是猫,2号线是猫,3号线是狗。

\2 – >捕获的组2的结果,即逗号(,)

所以在这段代码中,通过给出1和2,我们在代码中分别回忆或重复捕获的组1和2的结果。

按照代码的顺序(?:动物)应该是组1,(?:=)应该是组2,并继续..

但是通过给出?:我们使得匹配组未被捕获(其在匹配组中不计数,所以分组编号从第一个捕获组开始而不是非捕获),以便重复匹配结果-group(?:animal)不能在代码后面调用。

希望这解释了非捕获组的使用。

在这里input图像说明

在复杂的正则expression式中,如果您希望使用大量的组,其中一些用于重复匹配,另一些用于提供反向引用,则可能出现这种情况。 默认情况下,将匹配每个组的文本加载到反向引用数组中。 在我们有很多组的情况下,只需要能够从反向引用数组中引用它们中的一些,我们就可以覆盖这个默认行为来告诉正则expression式,某些组只有重复处理,并且不需要被捕获和存储在反向数组中。

那么我是一个JavaScript开发人员,并试图解释其有关JavaScript的意义。

考虑一个你想匹配cat is animal的场景cat is animal当你想匹配猫和动物,两者之间应该有一个。

  // this will ignore "is" as that's is what we want "cat is animal".match(/(cat)(?: is )(animal)/) ; result ["cat is animal", "cat", "animal"] // using lookahead pattern it will match only "cat" we can // use lookahead but the problem is we can not give anything // at the back of lookahead pattern "cat is animal".match(/cat(?= is animal)/) ; result ["cat"] //so I gave another grouping parenthesis for animal // in lookahead pattern to match animal as well "cat is animal".match(/(cat)(?= is (animal))/) ; result ["cat", "cat", "animal"] // we got extra cat in above example so removing another grouping "cat is animal".match(/cat(?= is (animal))/) ; result ["cat", "animal"] 

我遇到的一个有趣的事情是,你可以在一个非捕获组中有一个捕获组。 看看下面的正则expression式匹配的url:

 var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/; 

inputurlstring:

 var url = "http://www.ora.com:80/goodparts?q#fragment"; 

我的正则expression式中的第一个组(?:([A-Za-z]+):)是一个非捕获组,它与协议模式和冒号:字符即http:但是当我在代码下运行时,返回数组的第一个索引包含stringhttp当我想到http和冒号:都不会被报告,因为它们是在一个非捕获组内。

 console.debug(parse_url_regex.exec(url)); 

在这里输入图像描述

我想如果第一组(?:([A-Za-z]+):)是一个非捕获组,那么它为什么会在输出数组中返回httpstring。

所以如果你注意到非捕获组内有一个嵌套组([A-Za-z]+) 。 该嵌套组([A-Za-z]+)本身在非捕获组(?:([A-Za-z]+):)是一个捕获组(不具有?:在开始处)。 这就是为什么文本http仍然被捕获的原因,但是在非捕获组内部但在捕获组之外的冒号:字符不会被输出数组报告。

我想我会给你答案,不检查匹配成功没有使用捕获variables。

捕获variables$ 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 

如果您不想保存比赛,这很有用。