正则表达式中 ?: 的文档说明是什么?

30

前一段时间,我在正则表达式中(至少在PHP中)看到了一个技巧,可以通过在捕获组前面添加 ?: 来使其不进行捕获。

示例

$str = 'big blue ball';
$regex = '/b(ig|all)/';
preg_match_all($regex, $str, $matches);
var_dump($matches);

输出...

array(2) {
  [0]=>
  array(2) {
    [0]=>
    string(3) "big"
    [1]=>
    string(4) "ball"
  }
  [1]=>
  array(2) {
    [0]=>
    string(2) "ig"
    [1]=>
    string(3) "all"
  }
}
在这个例子中,我不关心括号中匹配的内容,所以我添加了?: ('/b(?:ig|all)/') 并得到输出。
array(1) {
  [0]=>
  array(2) {
    [0]=>
    string(3) "big"
    [1]=>
    string(4) "ball"
  }
}

这非常有用 - 至少我认为是。有时,您只是不想在匹配中添加不必要的值。

我试图查找文档和官方名称(我称之为非捕获组,但我想我以前听过这个名字)。

作为符号,似乎很难在 Google 上搜索。

我也查看了许多正则表达式参考指南,但没有提到。

? 为前缀,并出现在括号内的第一个字符会让我相信它与向前或向后查看有关。

那么,这些的正确名称是什么,我可以在哪里学到更多知识?


2
+1 因为我不知道 ?:(尽管它使正则表达式更加难以阅读) - DrColossos
干得好,伙计们!我给大家加一分。 - user187291
6个回答

33

它可以在官方文档的子模式页面上找到。

普通括号具有两个功能的事实并不总是有帮助的。有时候需要一个分组子模式,而不需要捕获。如果一个开括号后面跟着"?:", 则该子模式不进行捕获,并且在计算后续捕获子模式的数量时不计算在内。例如,如果字符串"the white queen"与模式the ((?:red|white) (king|queen))匹配,捕获的子字符串是"white queen"和"queen",它们的编号分别为1和2。最大捕获子字符串数量为99,所有子模式(包括捕获和非捕获)的最大数量为200。

还值得注意的是,您可以使用它为子模式设置选项。例如,如果您只希望子模式不区分大小写,可以这样做:

(?i:foo)bar

会匹配:

  • foobar
  • Foobar
  • FoObar
  • ...etc
但不是
  • fooBar
  • FooBAR
  • ...etc
哦,虽然官方文档实际上没有明确命名这个语法,但它在后面提到它是一个“非捕获子模式”(这完全合理,而且我也会这样称呼它,因为它并不是一个真正的“组”,而是一个子模式)...

此答案已被添加到 Stack Overflow 正则表达式 FAQ 中的“分组”章节。 - aliteralmind

8

(?:) 作为一个整体代表着一个非捕获组

Regular-expressions.info 提到了这个语法:

问号和冒号紧跟在左括号后面,是特殊的语法,用于告诉正则表达式引擎,这一对括号不应该创建一个反向引用。请注意,问号[...]是使前一个标记变成可选的正则表达式运算符。此运算符不能出现在左圆括号后面,因为单独的左括号不是有效的正则表达式标记。因此,没有混淆将问号作为使标记可选的运算符和问号作为更改一对圆括号属性的字符之间的区别。冒号表示我们要做出的更改是关闭捕获反向引用。


4

这是我找到的内容:

如果你不使用后向引用, 你可以将这个正则表达式优化为Set(?:Value)?。问号和冒号在开括号之后是特殊语法,告诉正则表达式引擎这一对括号不应该创建后向引用。请注意,开括号后面的问号与正则表达式末尾的问号无关。那个问号是使前一个令牌变成可选的正则表达式运算符。在开括号后面不能出现这个运算符,因为单独的开括号不是一个有效的正则表达式令牌。因此,在使一对圆括号的属性发生改变时,没有混淆使一个令牌变成可选的运算符和改变括号属性的字符之间的区别。冒号表示我们要做出的变化是关闭捕获后向引用。

http://www.regular-expressions.info/brackets.html


3

这在php手册中有提到,我相信其他任何一种语言的正则表达式部分也是如此...

普通括号具有两个功能,这并不总是有帮助的。有时需要一个分组子模式而不需要捕获要求。如果一个开括号后面跟着"?:", 子模式不会进行任何捕获,并且在计算后续捕获子模式数量时不被计算。

来源


2
PHP的preg_match_all使用PCRE(Perl兼容正则表达式)语法,其文档在这里。非捕获子模式在子模式章节中有说明。

让我相信它与前瞻或后顾有关。

不是的,有很多不同的功能是通过开括号问号触发的。前瞻/后顾只是你遇到的第一个。
很乱,因为许多选项必须挤在(?中,而不是给出自己更可读的语法,但这是必要的,以便将所有内容都放入先前不是有效表达式的序列中,在旧版regex中。

0

我不知道如何使用?:来完成这个任务,但是用简单的循环很容易实现:

$regex = '/b(ig|all)/';
$array = array(
    0 => array(0 => 'big', 1 => 'ball'),
    1 => array(0 => 'ig', 1 => 'all')
);
foreach ($array as $key => $row) {
    foreach ($row as $val) {
        if (!preg_match($regex, $val)) {
            unset($array[$key]);
        }
    }
}
print_r($array);

我知道。我只是举了一个例子。 - Alex Pliutau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接