《正则表达式经典实例(第2版)》——2.10 再次匹配先前匹配的文本

简介: 下一个记号是连字符,它会按照字面进行匹配。接着就遇到了反向引用。正则引擎会检查第一个捕获分组的内容:08。然后引擎会试图按照字面来匹配这个文本。如果该正则表达式是不区分大小写的,那么捕获分组也会按照这种方式进行匹配。

本节书摘来自异步社区《正则表达式经典实例(第2版)》一书中的第2章,第2.10节,作者: 【美】Jan Goyvaerts , Steven Levithan著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.10 再次匹配先前匹配的文本

问题描述
创建一个正则表达式来匹配按照yyyy-mm-dd格式的“神奇”日期。神奇日期指的是年份后2位与月份和该月的日期都是相同的数字。例如,2008-08-08就是一个神奇日期。你可以假设目标文本中的所有日期都是有效的。这个正则表达式并不需要考虑去掉像9999-99-99这样的日期,因为它们不会出现在目标文本中。你只需要找到神奇的日期即可。

解决方案

\b\d\d(\d\d)-\1-\1\b
正则选项:无
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby

讨论
为了在正则表达式中匹配先前匹配到的文本,我们首先必须记录上次匹配的文本。这可以使用捕获分组来实现,实例2.9中已经讲解过。在此之后,我们可以使用反向引用(backreference)来在该正则表达式中的任何地方匹配相同的文本。你可以使用一个反斜杠之后跟一个单个数字(1~9)来引用前9个捕获分组。而第10~99组,则要使用‹10›~‹99›。

screenshot不要使用01。它或者是一个八进制的转义,或者会产生一个错误。在本书中我们不会用到八进制转义,因为xFF这样的十六进制转义更加容易理解。
当正则表达式‹bdd(dd)-1-1b›遇到2008-08-08的时候,开始的‹dd›会匹配20。接着正则引擎会进入捕获分组,并记录目标文本中所在的位置。

在捕获分组中的‹dd›会匹配08,然后引擎会到达分组的右括号。在这个点上,匹配的部分08会被保存到1号捕获分组中。

下一个记号是连字符,它会按照字面进行匹配。接着就遇到了反向引用。正则引擎会检查第一个捕获分组的内容:08。然后引擎会试图按照字面来匹配这个文本。如果该正则表达式是不区分大小写的,那么捕获分组也会按照这种方式进行匹配。在这里,反向引用匹配成功。下一个连字符和反向引用也会匹配成功。最终,单词分界符会匹配目标文本的结尾,这样就找到了一个完整匹配:2008-08-08。现在捕获分组中依然保存的是08。

如果一个捕获分组被重复,这可以通过量词(实例2.12)或者是回溯(实例2.13)来实现,每次捕获分组匹配成功,都会覆盖之前保存的捕获分组匹配的内容。对该分组的反向引用只会匹配该分组最后一次捕获到的文本。

如果同一个正则表达式遇到2008-05-24 2007-07-07的时候,当‹bdd(dd)›匹配到2008的时候,该分组第一次捕获到的内容08,会被保存到第一个(也是唯一一个)捕获分组中。接下来,连字符会匹配它自身。反向引用在试图用05来匹配‹08›的时候,匹配失败。

由于在该正则表达式中不存在其他的选择分支,引擎会放弃匹配尝试。这包括清除所有的捕获分组。当引擎再次尝试的时候,从目标文本中的第一个0开始,‹1›不再存有任何文本内容。

接下来继续处理2008-05-24 2007-07-07,该分组下一次会捕获到内容是当‹bdd(dd)›匹配到2007的时候,它会把07保存起来。接下来,连字符匹配自身。现在反向引用会试图匹配‹07›。这次匹配是成功的,接着下一个连字符、反向引用以及单词边界都匹配成功。结果是找到了2007-07-07。

因为正则引擎是从前向后处理的,因此应当把捕获括号放到反向引用的前面。正则表达式‹bdd1-(dd)-1›和‹bdd1-1-(dd)b›永远不可能匹配到任何东西。因为这里的反向引用是在捕获分组之前出现的,而它还没有捕获到任何东西。除非你使用的是JavaScript,否则反向引用指向还没有进行匹配尝试的分组时,它总是会匹配失败。

还没有参与匹配的分组,并不等同于捕获到长度为0的分组。对一个长度为0的捕获分组的反向引用总是会匹配成功。当‹(^)1›匹配字符串的开始的时候,第一个捕获分组会捕获到^号的长度为0的匹配,从而‹1›会匹配成功。在实践中,这会发生在当所有捕获分组的内容都是可选的情况下。

screenshot JavaScript是我们所知道的唯一与正则表达式中几十年反向引用的传统相违背的流派。在JavaScript中,或者至少在遵循JavaScript标准的实现中,对一个还没有参与匹配的分组的反向引用总是会匹配成功,这同捕获了长度为0的匹配的分组的反向引用是一样的。因此,在JavaScript中,‹bdd1-1-(dd)b›会成功匹配12--34。

相关文章
|
1月前
|
Java 程序员
Java 异常处理与正则表达式详解,实例演练及最佳实践
在 Java 代码执行期间,可能会发生各种错误,包括程序员编码错误、用户输入错误以及其他不可预料的状况。 当错误发生时,Java 通常会停止并生成错误消息,这个过程称为抛出异常。 try...catch 语句 try 语句允许您定义一段代码块,并在其中测试是否发生错误。 catch 语句允许您定义一段代码块,当 try 块中发生错误时执行该代码块。 try 和 catch 关键字成对使用,语法如下:
42 0
|
4月前
|
机器学习/深度学习 存储 JavaScript
正则表达式基础语法与Java、JS使用实例
正则表达式基础语法与Java、JS使用实例
72 1
|
7月前
|
Java
Java正则表达式校验实例
Java正则表达式校验实例
49 0
|
1月前
|
Linux Perl
使用awk和正则表达式过滤文本或字符串 - 详细指南和示例
使用awk和正则表达式过滤文本或字符串 - 详细指南和示例
60 0
|
2月前
|
开发者 Python
Python中的正则表达式:re模块详解与实例
Python中的正则表达式:re模块详解与实例
|
7月前
|
Unix Linux
如何在 Linux 中使用 Grep 和正则表达式进行文本搜索?
如何在 Linux 中使用 Grep 和正则表达式进行文本搜索?
191 5
|
8月前
|
Shell
shell中正则表达式中字符的应用具体实例以及详解
shell中正则表达式中字符的应用具体实例以及详解
94 3
|
8月前
|
算法 C语言 数据安全/隐私保护
【C++技能树】快速文本匹配 --正则表达式介绍与C++正则表达式使用
假设要判断一个QQ号是否有效,他必须满足以下三个规则
70 0
|
10月前
|
Python
34.从入门到精通:Python3 正则表达式检索和替换 repl 参数是一个函数 正则表达式对象 正则表达式修饰符 - 可选标志 正则表达式模式* 正则表达式实例
34.从入门到精通:Python3 正则表达式检索和替换 repl 参数是一个函数 正则表达式对象 正则表达式修饰符 - 可选标志 正则表达式模式* 正则表达式实例
|
11月前
|
Python
Python正则表达式匹配电话号码和邮箱实例演示,正则表达式的基本用法
Python正则表达式匹配电话号码和邮箱实例演示,正则表达式的基本用法
204 0