正则表达“匹配”与“捕捉”

时间:2014-01-18 05:41:37

标签: regex

我一直在查找正则表达式教程,试图了解它们并且正在享受此链接中的教程,直到出现此问题:http://regexone.com/lesson/12

我似乎无法弄清楚“匹配”和“捕获”之间的区别是什么。我写的任何内容似乎都没有选择“捕获”部分下的文本(甚至不是.*)。

修改:以下是让我感到困惑的教程示例:(.* (.*))被认为是正确的而(.* .*)不是。这是教程中的问题还是我不​​理解的东西?

4 个答案:

答案 0 :(得分:7)

匹配

当引擎匹配字符串或整体的一部分但确实返回

捕获:

当引擎匹配字符串或整体的一部分并返回 某些内容

- 返回的含义是什么?

当你需要检查/存储/验证/工作/喜欢你的正则表达式匹配它的字符串的一部分之后你需要捕获组(...)

在您的示例中,此正则表达式.*?\d+只匹配日期和年份See here

此正则表达式.*?(\d+)与整体相匹配并捕获年份See here

(.*?(\d+))将匹配整体并分别捕捉整个和年份See here

* 请注意标题为“匹配组

”的右下方框

所以回来......

1

preg_match("/.*?\d+/", "Jan 1987", $match);
print_r($match);

<强>输出

Array
(
    [0] => Jan 1987
)

2:

preg_match("/(.*?\d+)/", "Jan 1987", $match);
print_r($match);

<强>输出

Array
(
    [0] => Jan 1987
    [1] => Jan 1987
)

3:

preg_match("/(.*?(\d+))/", "Jan 1987", $match);
print_r($match);

<强>输出

Array
(
    [0] => Jan 1987
    [1] => Jan 1987
    [2] => 1987
)

正如您在上一个示例中所看到的,我们在阵列中有2个捕获组,索引为 1 2 0 始终是匹配的字符串,但它没有被捕获。

答案 1 :(得分:2)

在regexp中捕获意味着您不仅对匹配感兴趣(正在查找与您的正则表达式匹配的字符串),而且您还对以后使用匹配字符串的特定部分感兴趣。

例如,您链接到的教程的答案为(\w{3}\s+(\d+))

现在,为什么?

简单地匹配日期字符串就足以编写\w{3}\s+\d+(3个字符,后跟一个或多个空格,后跟一个或多个数字),但将捕获组添加到表达式中(捕获group只是包含在括号()中的任何内容)将允许我稍后提取整个表达式(使用“$ 1”,因为最外面的一对括号是解析器遇到的第一个)或只是年份(使用“$ 2”,因为\d+周围的第二对括号是正则表达式解析器遇到的第二对括号。

当您不仅对将字符串匹配到模式,而且还从匹配的字符串中提取数据或以任何方式修改它们时,

捕获组都会派上用场。例如,假设您想在教程中的每个日期添加5年 - 能够从匹配的字符串中提取年份部分(使用$2)会派上用场

答案 2 :(得分:1)

简而言之,&#34; Capture&#34;将收集的值保存在特殊位置,以便稍后访问。

正如一些人已经指出的那样,捕获的东西可以在以后使用过&#39;以相同的模式,以便

/(ab*c):\1/

将匹配ac:ac,或abc:abc,或abbc:abbc等。(ab * c)将匹配a,任意数量的b,然后是c。无论它匹配什么都被捕获了#39;在许多编程和脚本语言中,像\ 1,\ 2等语法具有指向第一,第二等捕获的特殊含义。由于第一个可能是abbc,因此\ 1位必须仅匹配abbc,因此唯一可能的完全匹配将是&#39; abbc:abbc&#39;

Perl(我认为)PHP都允许使用\ 1 \ 2语法,但它们也使用$ 1 $ 2等,这被认为是更现代的。许多语言已经从Perl中获得了强大的RegEx引擎,因此世界上越来越多地使用它。

由于您的示例问题似乎在PHP站点上,因此PHP中典型的$ 1使用是:

/(ab*c)(de*f)/

然后(例如下一行代码)

$x = $1 . $2;   # I hope that's PHP syntax for concatenation!

因此捕获可用,直到您下次使用正则表达式。根据所使用的编程语言,下一个模式匹配可能会破坏这些捕获的值,或者可以通过特殊语法或使用该语言永久获取它们。

答案 3 :(得分:0)

从你的例子中看看这两个正则表达式

# first
/(... (\d\d\d\d))/
#second
/... \d\d\d\d/

他们都匹配“1965年6月”和“2000年5月” (顺便提一下很多其他的东西,比如“555 1234”)

第二个匹配它 - yesno

所以你可以说

if ($x=~/... \d\d\d\d/){do something}

第一个捕获如此

/(... (\d\d\d\d))/
print $1,";;;",$2

将打印“Jun 1967 ;;; 1967”