本网站上的更多内容 |
简介 |
正则表达式快速入门 |
正则表达式教程 |
替换字符串教程 |
应用程序和语言 |
正则表达式示例 |
正则表达式参考 |
替换字符串参考 |
书籍评论 |
可打印 PDF |
关于本网站 |
RSS 提要和博客 |
已经介绍了一个重复运算符或量词:问号。它告诉引擎尝试匹配前一个标记零次或一次,实际上使其成为可选的。
星号或乘号告诉引擎尝试匹配前一个标记零次或多次。加号告诉引擎尝试匹配前一个标记一次或多次。 <[A-Za-z][A-Za-z0-9]*> 匹配没有任何属性的 HTML 标记。尖括号是 文字。第一个 字符类 匹配一个字母。第二个字符类匹配一个字母或数字。星号重复第二个字符类。由于我们使用了星号,因此即使第二个字符类没有匹配任何内容也没有关系。因此,我们的正则表达式将匹配 <B> 这样的标记。在匹配 <HTML> 时,第一个字符类将匹配 H。星号将导致第二个字符类重复三次,分别匹配 T、M 和 L。
我也可以使用 <[A-Za-z0-9]+>。我没有使用,因为此正则表达式将匹配 <1>,这不是一个有效的 HTML 标记。但是,如果您知道要搜索的字符串不包含任何此类无效标记,则此正则表达式可能就足够了。
还有一个量词,允许您指定一个标记可以重复多少次。语法是 {min,max},其中 min 是零或一个正整数,表示最小匹配次数,而 max 是一个等于或大于 min 的整数,表示最大匹配次数。如果存在逗号但省略了 max,则最大匹配次数为无穷大。因此,{0,1} 与 ? 相同,{0,} 与 * 相同,{1,} 与 + 相同。省略逗号和 max 告诉引擎重复标记恰好 min 次。
您可以使用 \b[1-9][0-9]{3}\b 匹配 1000 到 9999 之间的一个数字。 \b[1-9][0-9]{2,4}\b 匹配 100 到 99999 之间的一个数字。请注意使用了 词边界。
假设你想使用正则表达式匹配一个 HTML 标签。你知道输入将是一个有效的 HTML 文件,所以正则表达式不需要排除任何尖括号的无效用法。如果它位于尖括号之间,它就是一个 HTML 标签。
大多数正则表达式新手会尝试使用 <.+>。当他们在像 This is a <EM>first</EM> test 这样的字符串上测试它时,他们会感到惊讶。你可能希望正则表达式匹配 <EM>,然后在该匹配之后继续匹配 </EM>。
但它没有。正则表达式将匹配 <EM>first</EM>。显然不是我们想要的。原因是加号是贪婪的。也就是说,加号会导致正则表达式引擎尽可能多地重复前一个标记。只有当这导致整个正则表达式失败时,正则表达式引擎才会回溯。也就是说,它将返回加号,让它放弃最后一次迭代,并继续执行正则表达式的其余部分。让我们深入了解正则表达式引擎,详细了解它是如何工作的,以及为什么这会导致我们的正则表达式失败。在那之后,我将向你展示两个可能的解决方案。
与加号一样,星号和使用大括号的重复也是贪婪的。
正则表达式中的第一个标记是 <。这是一个文字。正如我们已经知道的,它将匹配的第一个位置是字符串中的第一个 <。下一个标记是点,它匹配除换行符之外的任何字符。点被加号重复。加号是贪婪的。因此,引擎将尽可能多地重复点。点匹配 E,所以正则表达式继续尝试用点匹配下一个字符。M 被匹配,点再次被重复一次。下一个字符是 >。你现在应该看到问题了。点匹配 >,引擎继续重复点。点将匹配字符串中所有剩余的字符。当引擎到达字符串末尾后的空隙时,点失败。只有在这一点上,正则表达式引擎才会继续执行下一个标记:>。
到目前为止,<.+ 已经匹配了 <EM>first</EM> test,引擎已经到达字符串的末尾。> 在这里无法匹配。引擎记住加号重复点的次数比要求的次数多。(记住,加号要求点只匹配一次。)引擎不会承认失败,而是会回溯。它将减少加号的重复次数,然后继续尝试正则表达式的其余部分。
所以 .+ 的匹配被减少到 EM>first</EM> tes。正则表达式中的下一个标记仍然是 >。但现在字符串中的下一个字符是最后一个 t。同样,它们无法匹配,导致引擎进一步回溯。到目前为止的总匹配减少到 <EM>first</EM> te。但 > 仍然无法匹配。因此,引擎继续回溯,直到 .+ 的匹配减少到 EM>first</EM。现在,> 可以匹配字符串中的下一个字符。正则表达式中的最后一个标记已经匹配。引擎报告 <EM>first</EM> 已成功匹配。
请记住,正则表达式引擎热衷于返回匹配项。它不会继续回溯以查看是否存在其他可能的匹配项。它将报告找到的第一个有效匹配项。由于贪婪,这是最左边的最长匹配项。
解决此问题的快速方法是使加号变为懒惰而不是贪婪。懒惰量词有时也称为“非贪婪”或“勉强”。您可以在正则表达式中加号后加上问号来实现。您还可以对星号、花括号和问号本身执行相同的操作。因此,我们的示例变为 <.+?>。让我们再次查看正则表达式引擎内部。
同样,< 匹配字符串中的第一个 <。下一个标记是点,这次由懒惰加号重复。这告诉正则表达式引擎尽可能少地重复点。最少为一个。因此,引擎用 E 匹配点。要求已得到满足,引擎继续使用 > 和 M。这失败了。同样,引擎将回溯。但这一次,回溯将强制懒惰加号扩展而不是缩小其范围。因此,.+ 的匹配项扩展为 EM,引擎再次尝试继续使用 >。现在,> 已成功匹配。正则表达式中的最后一个标记已匹配。引擎报告 <EM> 已成功匹配。更像这样。
在这种情况下,有一个比使加号变为懒惰更好的选择。我们可以使用贪婪加号和否定字符类:<[^>]+>。之所以这样做更好,是因为回溯。当使用懒惰加号时,引擎必须为它试图匹配的 HTML 标记中的每个字符回溯。当使用否定字符类时,当字符串包含有效的 HTML 代码时,根本不会发生回溯。回溯会减慢正则表达式引擎的速度。在文本编辑器中进行单次搜索时,您不会注意到差异。但是,当在您编写的脚本中的紧密循环中或在 EditPad Pro 的自定义语法着色方案中重复使用此类正则表达式时,您将节省大量的 CPU 周期。
只有 regex 指导引擎 回溯。文本指导引擎不回溯,因此不会受到速度损失。但它们也不支持惰性量词。
\Q…\E 序列 转义一个字符字符串,将它们作为字面字符进行匹配。转义的字符被视为单个字符。如果在 \E 后放置量词,则它将只应用于最后一个字符。例如,如果将 *\d+*+ 应用于 *\d+**\d+*,则匹配结果将是 *\d+**。只有星号被重复。Java 4 和 5 有一个 bug,导致整个 \Q…E 序列被重复,从而将整个主题字符串作为匹配结果。此问题已在 Java 6 中修复。
| 快速入门 | 教程 | 工具和语言 | 示例 | 参考 | 书籍评论 |
| 简介 | 目录 | 特殊字符 | 不可打印字符 | Regex 引擎内部 | 字符类 | 字符类减法 | 字符类交集 | 简写字符类 | 点 | 锚 | 单词边界 | 交替 | 可选项 | 重复 | 分组和捕获 | 反向引用 | 反向引用,第 2 部分 | 命名组 | 相对反向引用 | 分支重置组 | 自由间距和注释 | Unicode | 模式修饰符 | 原子分组 | 占有量词 | 前瞻和后顾 | 前瞻和后顾,第 2 部分 | 从匹配中保留文本 | 条件 | 平衡组 | 递归 | 子例程 | 无限递归 | 递归和量词 | 递归和捕获 | 递归和反向引用 | 递归和回溯 | POSIX 方括号表达式 | 零长度匹配 | 继续匹配 |
页面网址:https://regexper.cn/repeat.html
页面上次更新时间:2021 年 8 月 12 日
网站上次更新时间:2024 年 3 月 15 日
版权所有 © 2003-2024 Jan Goyvaerts。保留所有权利。