非捕获组,即(?:)
在正则表达式中是如何使用的?它们有什么好处?
非捕获组,即(?:)
在正则表达式中是如何使用的?它们有什么好处?
为了补充这个帖子中其他好的回答,我想要加入我发现的一个有趣的观察。
发现:你可以在一个非捕获组中放置一个捕获组。
问题详情:请看下面用于匹配Web URL的正则表达式:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
这是我的输入网址字符串:
var url = "http://www.ora.com:80/goodparts?q#fragment";
我的正则表达式中的第一个组是(?:([A-Za-z]+):)
,它是一个非捕获组,匹配协议方案(http
)和冒号(:
)字符。继续匹配后会匹配到http:
。但是当我运行下面的代码时:
console.debug(parse_url_regex.exec(url));
我可以看到返回的数组的第1个索引包含字符串http
(请参阅截图)。
此时,我的想法是http
和冒号:
都不会在输出中报告,因为它们位于一个非捕获组内。如果第一个正则表达式组(?:([A-Za-z]+):)
是一个非捕获组,那么为什么它会在输出数组中返回http
字符串呢?
解释:如果您注意到,([A-Za-z]+)
是一个捕获组(开头没有?:
)。但是,该捕获组本身位于非捕获组(?:([A-Za-z]+):)
中,并跟随一个冒号:
字符。这就是为什么文本http
仍然被捕获,但落在非捕获组内(但在捕获组外部)的冒号:
字符不会在输出数组中报告的原因。
我是一名 JavaScript 开发者,将尝试解释其在 JavaScript 中的重要性。
考虑这样一个情景:你想匹配 cat is animal
,
当你想要匹配 cat 和 animal 并且它们两者之间应该有一个 is
。
// 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"]
让我举一个地理坐标的例子,下面匹配了两个组
Latitude,Longitude
([+-]?\d+(?:\.\d+)?),([+-]?\d+(?:\.\d+)?)
让我们取一个坐标点 ([+-]?\d+(?:\.\d+)?)
坐标可以是整数,比如 58
,也可以是小数,比如 58.666
。因此,可选的(.666
)第二部分 (\.\d+)?
被提及。
(...)? - for optional
但是它被括号包围,这将成为另一组匹配。我们不希望有两次匹配,一次是对于58
,另一次是对于.666
,我们需要一个匹配的纬度。这就是非捕获组(?:)
。
使用非捕获组[+-]?\d+(?:\.\d+)?
,58.666和58都是单个匹配。
(?: ... ) 表示一个组 ( ... ) 但不捕获匹配数据。它比标准的捕获组要高效得多。当你想要分组但不需要以后重用时,可以使用它。@Toto
这非常简单,我们可以通过一个简单的日期示例来理解,假设日期为2019年1月1日或2019年5月2日或其他任何日期,我们只想将其转换为dd/mm/yyyy格式,不需要月份的名称(例如January或February),因此为了捕获数字部分而不是(可选)后缀,您可以使用非捕获组。
所以正则表达式应该是:
([0-9]+)(?:January|February)?
就是这么简单。
我来翻译一下。关于IT技术,有一个需要注意的问题:在使用捕获变量时,一定要检查匹配是否成功。
如果匹配失败,那么捕获变量如$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
如果您不想保存匹配结果,这将非常有用。
打开你的 Google Chrome 开发者工具,然后切换到控制台选项卡,并输入以下内容:
"Peace".match(/(\w)(\w)(\w)/)
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
"Peace".match(/(?:\w)(\w)(\w)/)
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]