《正则表达式经典实例(第2版)》——2.8 匹配多个选择分支之一

2.8 匹配多个选择分支之一

问题描述
创建一个正则表达式,当把它重复应用到目标文本Mary, Jane, and Sue went to Mary's house之上时,会匹配到Mary、Jane、Sue,且能再次匹配到Mary。之后再进行的匹配尝试都会失败。

解决方案

Mary|Jane|Sue
正则选项:无
正则流派:.NET、Java、JavaScript、PCRE、Perl、Python、Ruby

讨论
竖线(vertical bar),或称作管道符号(pipe symbol),会把正则表达式拆分成多个选择分支。‹Mary|Jane|Sue›会在每次匹配尝试时匹配Mary,或者Jane,或者Sue。每次只会匹配一个名字,但是每次却可以匹配不同的名字。

本书中的所有正则表达式流派都会使用正则制导的引擎。正则表达式依赖于这台引擎来工作。这里所说的正则制导1FF的含义是,在目标文本中的每个字符位置会首先匹配该正则表达式的所有可能排列,然后才会到下一个字符位置进行匹配尝试。

当你把‹Mary|Jane|Sue›应用到Mary, Jane, and Sue went to Mary's house的时候,在字符串起始处立即就会找到匹配Mary。

当你把同一个正则表达式应用到余下的字符串的时候,比如说,你可以在文本编辑器中单击“查找下一个”,正则引擎就会尝试在该字符串中的第一个逗号处匹配‹Mary›。匹配会失败。然后,它会在同一个位置尝试去匹配‹Jane›,这也会失败。接着在逗号处匹配‹Sue›,当然也会失败。只有在所有匹配都失败之后,正则引擎才会前进到字符串中的下一个字符。从第一个空格开始匹配,3个选择分支都会得到同样的失败结果。

从字母J开始匹配的时候,第一个选择分支‹Mary›会出现匹配失败。接着第二个选择分支,也就是‹Jane›,会在字母J处匹配成功。它匹配的是Jane。正则引擎宣布匹配成功。

需要注意的是:虽然在目标文本中还存在另外一个Mary,而且在正则表达式中‹Mary›出现在‹Jane›之前,但是这里匹配到的依然是Jane。至少在这个例子中,正则表达式中各分支的顺序并不重要。正则表达式会查找最左边的匹配。它会从左向右扫描目标文本,在扫描的每一步中都会尝试正则表达式中的所有选择分支,而当其中任意一个选择分支产生一个合法匹配的时候,匹配过程就会停在这个位置。

如果我们再次对字符串余下部分进行查找,那么会找到Sue。而第四次查找则会再一次找到Mary。如果你告诉正则引擎进行第五次查找,就会失败,因为这三个选择分支都无法匹配余下的’s house字符串。

只有当在字符串中的同一个位置存在两个选择分支同时匹配的时候,正则式中的选择分支的顺序才有意义。例如,正则式‹Jane|Janet›在匹配目标文本Her name is Janet的时候,就会有两个选择分支在同一位置出现匹配。在此正则表达式中并不存在单词边界。事实上,‹Jane›是否只匹配到Her name is Janet中的单词Janet的一部分并不重要。

‹Jane|Janet›之所以会匹配到Her name is Janet中的Jane,是因为一个正则制导的正则表达式引擎是遵循“浅尝辄止”的工作原则的(eager)。除了会从左向右扫描目标文本,查找最左匹配之外,它还会从左向右扫描正则式中的选择分支。而一旦它找到一个匹配的选择分支,正则引擎就会立即停止。

当‹Jane|Janet›到达了Her name is Janet中的J的时候,第一个选择分支‹Jane›,成功匹配。第二个选择分支则根本没有进行尝试。如果我们告诉引擎接着查找下一个匹配的话,这时候在目标文本中剩下的只有t。此时两个选择分支都不能成功匹配。

要想不让Jane抢夺Janet的光环,有两种方式。第一种方式是把较长的选择分支放在前面:‹Janet|Jane›。另外一种更为可靠的方式是清晰地表达我们所期望的结果:我们在查找名字,而名字应该是完整的单词。正则表达式并不会处理单词,但是它们可以处理单词边界。

因此,‹bJaneb|bJanetb›和‹bJanetb|bJaneb›都会匹配到Her name is Janet中的Janet。由于单词边界的原因,只有一个选择分支会成功匹配。在这里我们看到选择分支的顺序依然无关紧要。

时间: 2025-01-01 10:47:49

《正则表达式经典实例(第2版)》——2.8 匹配多个选择分支之一的相关文章

《正则表达式经典实例(第2版)》——导读

** 前言 **正则表达式在过去十多年间越来越普及.如今,所有常用的编程语言都会包含一个强大的正则表达式函数库,甚至在语言本身就内嵌了对于正则表达式的支持.许多开发人员都会利用这些正则表达式的功能,在应用程序中为用户提供使用正则表达式对其数据进行查找或者过滤的能力.正则表达式已经无处不在.随着正则表达式的广泛采用,出现了许多相关的著作.其中大多数都很好地讲解了正则表达式的语法,并且还会提供一些例子以及参考实现.然而,我们还没有看到有任何一本书能够针对处理计算机和不同因特网应用上的文本所遇到的各种

《正则表达式经典实例(第2版)》——2.14 消除不必要的回溯

2.14 消除不必要的回溯 问题描述上一个实例解释了贪心和懒惰量词之间的区别,以及它们是如何进行回溯的.在有些情形下,这种回溯是不必要的. ‹bd+b›使用了一个贪心量词,而‹bd+?b›使用的是懒惰量词.它们都会匹配相同的内容:一个整数.如果给它们同样的目标文本,它们都会找到完全一样的匹配.在这里所做的任何回溯都是不必要的.试着改写这个正则表达式,明确地消除所有回溯,使正则表达式更加高效. 解决方案 \b\d++\b 正则选项:无 正则流派:Java.PCRE.Perl 5.10.Ruby 1

《正则表达式经典实例(第2版)》——2.9 分组和捕获匹配中的子串

2.9 分组和捕获匹配中的子串 问题描述 改进匹配Mary.Jane或Sue的正则表达式,使之只能匹配完整单词.使用分组来实现这个功能,整个正则表达式只需要一对单词分界符,而不是给每个选择分支都使用一对分界符. 创建一个正则表达式,使之匹配yyyy-mm-dd格式的任意日期,并且分别捕获年.月和日.目标是在处理匹配的代码中可以更容易处理这些分别捕获的值.你可以假设目标文本中的所有日期都是合法的.正则表达式不必要考虑去掉像9999-99-99这样的非法数据,因为它们根本不可能出现在目标文本中. 解

《正则表达式经典实例(第2版)》——2.3 匹配多个字符之一

2.3 匹配多个字符之一 问题描述 创建一个正则表达式来匹配calendar的所有常见的错误拼写形式,使你能够在一份文档中找到这个单词而无需依赖作者的拼写能力.在每个元音位置都允许使用a或者e.创建另外一个正则表达式来匹配一个单个的十六进制字符.再创建一个正则表达式来匹配不属于十六进制字符的单个字符. 本节中的这个问题用于解释一个重要的.经常使用的正则结构-字符组(character class). 解决方案 错误拼写的calendar c[ae]l[ae]nd[ae]r 正则选项:无 正则流派

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

2.10 再次匹配先前匹配的文本 问题描述创建一个正则表达式来匹配按照yyyy-mm-dd格式的"神奇"日期.神奇日期指的是年份后2位与月份和该月的日期都是相同的数字.例如,2008-08-08就是一个神奇日期.你可以假设目标文本中的所有日期都是有效的.这个正则表达式并不需要考虑去掉像9999-99-99这样的日期,因为它们不会出现在目标文本中.你只需要找到神奇的日期即可. 解决方案 \b\d\d(\d\d)-\1-\1\b 正则选项:无 正则流派:.NET.Java.JavaScri

半小时精通正则表达式 经典实例介绍_正则表达式

开篇,还是得说说 ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明 如果您是新手,猜你取消 正则表达式30分钟入门教程"^The": 开头一定要有"The"字符串; "of despair$": 结尾一定要有"of despair" 的字符串; 那么, "^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配 "notice": 匹配包含no

半小时精通正则表达式 经典实例介绍

开篇,还是得说说 ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明 如果您是新手,猜你取消 正则表达式30分钟入门教程 "^The": 开头一定要有"The"字符串; "of despair$": 结尾一定要有"of despair" 的字符串; 那么, "^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配 "notice": 匹配包含n

《正则表达式经典实例(第2版)》——1.3 正则表达式工具

1.3 正则表达式工具 除非已经拥有了相当长的使用正则表达式编程的经验,否则建议你先在一个工具中试验一下正则表达式,而不是直接在源代码中使用它们.本章和第2章中提供的正则表达式示例都是原始正则表达式,其中并不包含编程语言(即使是Unlx shell)所必需的额外的转义符号.因此可以直接把这些正则表达式输入到一个应用程序的查找框中. 第3章讲解如何把正则表达式整合到源代码中.把一个字面的(literal)正则表达式作为一个字符串引用,会让它更加难懂,因为字符串的转义规则会与正则表达式的转义规则混杂

《正则表达式经典实例(第2版)》——2.2 匹配不可打印字符

2.2 匹配不可打印字符 问题描述 匹配一个包含下列ASCII控制字符的字符串:振铃符(bell).转义符(escape).换页符(form feed).换行符(line feed).回车符(carriage return).水平制表符(horizontal tab)和垂直制表符(vertical tab).这些字符的十六进制ASCII编码分别是07.1B.0C.0A.0D.09.0B. 下面演示了转义序列的用法,以及如何以十六进制编码代表字符. 解决方案 \a\e\f\n\r\t\v 正则选项