什么是非捕获组? 问号跟一个冒号(?:)是什么意思?
读了一些教程后,我仍然不明白。
有人可以解释一下?:
是用来做什么的?
让我试着用一个例子来解释这一点。
考虑以下文字:
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]+):)
是一个非捕获组,那么它为什么会在输出数组中返回http
string。
所以如果你注意到非捕获组内有一个嵌套组([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
如果您不想保存比赛,这很有用。