《正则表达式经典实例(第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。

相关文章
|
6月前
|
Java 程序员
Java 异常处理与正则表达式详解,实例演练及最佳实践
在 Java 代码执行期间,可能会发生各种错误,包括程序员编码错误、用户输入错误以及其他不可预料的状况。 当错误发生时,Java 通常会停止并生成错误消息,这个过程称为抛出异常。 try...catch 语句 try 语句允许您定义一段代码块,并在其中测试是否发生错误。 catch 语句允许您定义一段代码块,当 try 块中发生错误时执行该代码块。 try 和 catch 关键字成对使用,语法如下:
98 0
|
6月前
|
机器学习/深度学习 存储 JavaScript
正则表达式基础语法与Java、JS使用实例
正则表达式基础语法与Java、JS使用实例
100 1
|
Java
Java正则表达式校验实例
Java正则表达式校验实例
80 0
|
3月前
|
SQL 数据处理 数据库
SQL正则表达式应用:文本数据处理的强大工具——深入探讨数据验证、模式搜索、字符替换等核心功能及性能优化和兼容性问题
【8月更文挑战第31天】SQL正则表达式是数据库管理和应用开发中处理文本数据的强大工具,支持数据验证、模式搜索和字符替换等功能。本文通过问答形式介绍了其基本概念、使用方法及注意事项,帮助读者掌握这一重要技能,提升文本数据处理效率。尽管功能强大,但在不同数据库系统中可能存在兼容性问题,需谨慎使用以优化性能。
47 0
|
3月前
|
SQL 分布式计算 算法
【python】python指南(三):使用正则表达式re提取文本中的http链接
【python】python指南(三):使用正则表达式re提取文本中的http链接
26 0
|
4月前
|
Java
正则表达式在Java中的应用与实例
正则表达式在Java中的应用与实例
|
5月前
|
Python
Python正则表达式详解:掌握文本匹配的魔法
Python正则表达式详解:掌握文本匹配的魔法
|
6月前
|
Rust 监控 安全
【专栏】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式
【4月更文挑战第28天】`ripgrep`(rg)是Linux下快速、内存高效的文本搜索工具,用Rust编写,支持PCRE2正则表达式。相比`grep`,它在处理大文件和复杂模式时更具优势。安装`rg`可通过软件包管理器,如在Debian系系统中使用`sudo apt install ripgrep`。基本用法包括简单搜索、递归搜索、忽略大小写、显示行号等。高级功能包括固定字符串搜索、多文件匹配、并行搜索、排除选项和区域搜索。适用于日志分析、代码审查等场景,是提升工作效率的利器。
501 4
|
6月前
|
机器学习/深度学习 Shell 开发工具
正则表达式 与文本三剑客(sed grep awk)
正则表达式 与文本三剑客(sed grep awk)
|
6月前
探索正则表达式:强大文本匹配与处理工具
探索正则表达式:强大文本匹配与处理工具