正则表达式“匹配”与“捕获”

Regular Expression "Matching" vs "Capturing"

提问人:asimes 提问时间:1/18/2014 最后编辑:asimes 更新时间:1/20/2014 访问量:17542

问:

我一直在查找正则表达式教程,试图掌握它们的窍门,并且一直很喜欢此链接中的教程,直到出现此问题:http://regexone.com/lesson/12

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

编辑:这是一个让我感到困惑的教程示例:被认为是正确的,而不是。这是教程的问题还是我不理解的地方?(.* (.*))(.* .*)

正则表达式

评论

1赞 vish 1/18/2014
匹配是一个是不是的问题,它匹配或不匹配。捕获 返回表达式的一部分(段落中的部分) 您可以捕获多个部分(可能是嵌套的)并返回一个列表
0赞 asimes 1/18/2014
我不确定返回在正则表达式中意味着什么,我只是了解匹配
0赞 Felix Kling 1/18/2014
通过“捕获”,您可以告诉引擎匹配的哪些部分应该存储在某种寄存器中,以便您可以在表达式本身中使用该值,或者在某些替换值中使用该值,具体取决于您使用表达式的函数。例如,将匹配任何重复的字母。指示要捕获此部分 natch 的值,并允许您访问第一个(且仅在本例中)捕获的值。或者换句话说:匹配第一个捕获组 () 匹配的任何内容。([a-z])\1(...)\1\1(...)
0赞 Bryan Elliott 1/18/2014
您最熟悉的编程语言是什么?使用您熟悉的编程语言可以很容易地形成一个清晰的例子。
0赞 asimes 1/18/2014
我熟悉几种语言,但我想我唯一一次在编程语言中看到正则表达式是在已弃用的 PHP 中

答:

0赞 vish 1/18/2014 #1

看看这 2 个正则表达式 - 从您的示例中

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

它们都匹配“Jun 1965”和“May 2000”
(顺便说一句,还有许多其他内容,例如“555 1234”)

第二个正好匹配它 - Yesno

所以你可以说

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

第一个捕捉到了

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

将打印“Jun 1967;;;1967"

评论

0赞 asimes 1/20/2014
我刚刚意识到你不是省略号再看一遍,所以现在它更有意义了。那和呢?...$1$2
0赞 Taylor Hx 1/20/2014
@asimes,被称为“反向引用”。它们是特殊字符,用于保存捕获组内匹配的任何数据。基本语法是美元符号,后跟一个数字,等于捕获组的顺序。在上面的例子中,保持是因为它与最外层的一对括号对齐,而保持就像它与第二对括号对齐一样。$1$2$$1... \d\d\d\d$2\d\d\d\d
0赞 tripleee 1/20/2014
捕获的字符串存储在 、 等中,只要有带括号的表达,就算起左起的左括号。$1$2$3
0赞 tripleee 1/20/2014
当正则表达式本身引用匹配项时,适当的“反向引用”就会发挥作用。例如,将匹配“aba”和“bbb”,但不匹配“abb”或“abc”;回指第一个带括号的表达式,这里是第一个字符;因此,第三个字符必须与第一个字符相同。该小组也将在 中被捕获。(.).\1\1$1
6赞 radai 1/20/2014 #2

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

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

现在,为什么?

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

当您不仅对将字符串与模式匹配感兴趣,而且还对从匹配的字符串中提取数据或以任何方式修改它们感兴趣时,捕获组会派上用场。例如,假设您想在本教程中为每个日期添加 5 年 - 能够从匹配的字符串中提取年份部分(使用 )会派上用场$2

评论

1赞 asimes 1/20/2014
好的,谢谢你。我假设 、 等是特定于 PHP 的。在这种情况下,您能指出我用于生成这些变量的 PHP 函数的引用吗?您真的必须将它们作为单个变量而不是数组来访问吗?$1$2
1赞 radai 1/20/2014
捕获的概念是所有正则表达式实现的通用概念。特别是在 PHP 中,访问捕获组的方法似乎是通过捕获索引访问数组。请参阅此处的preg_match文档 - php.net/manual/en/function.preg-match.phpmatches
26赞 revo 1/20/2014 #3

匹配:

当 engine 匹配字符串的一部分或整体但不返回任何内容时。

捕获:

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

-- 返回的意义是什么?

当您需要检查/存储/验证/工作/爱正则表达式匹配的字符串的一部分时,您需要捕获组 (...)

在您的示例中,此正则表达式仅匹配日期和年份 请参阅此处.*?\d+

这个正则表达式匹配整体并捕获年份 看这里.*?(\d+)

并将匹配整体并分别捕获整体和年份 看这里(.*?(\d+))

*请注意右下角标题为“匹配组”的框

所以回来了......

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 个捕获组,索引分别为 12,并且 0 始终是匹配的字符串,但它没有被捕获。

评论

0赞 Ben Butterworth 10/10/2020
为什么要使用?是要使数字前面的字符串成为可选的,以允许数字捕获组捕获所有数字,而不仅仅是第一个数字?这是我在使用 regex101.com 比较 和 之后得出的结论。我发现有趣的是,对于第一种情况:(仅捕获整个字符串),该问号不执行任何操作,但已包含在内。?(.*?(\d+))(.*(\d+)/.*?\d+/
0赞 revo 10/10/2020
@BenButterworth您可能会发现这 stackoverflow.com/q/2301285/1020526
4赞 user1646075 1/20/2014 #4

简而言之,“捕获”将收集的值保存在一个特殊位置,以便您以后可以访问它。

正如一些人所指出的,捕获的东西可以“稍后”以相同的模式使用,因此

/(ab*c):\1/

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

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

由于您的示例问题似乎在 PHP 网站上,因此 PHP 中 1 美元的典型用途是:

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

然后稍后(例如下一行代码)

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

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

评论

0赞 asimes 1/20/2014
谢谢,这确实是PHP串联