跳到主要内容

7.2 子表达式的嵌套

子表达式允许嵌套。事实上,子表达式允许多重嵌套,这种嵌套的层次在理论上没有限制,但在实际工作中还是应该遵循适可而止的原则。

多重嵌套的子表达式可以构造出功能极其强大的正则表达式来,但那难免会让模式变得难以阅读和理解,而这也正是很多人觉得正则表达式难以学习和掌握的原因之一。这种表面现象掩盖了这样一个事实:绝大多数嵌套子表达式都没有它们看上去那么复杂。

为了演示嵌套子表达式的用法,我们再去看看刚才那个匹配 IP 地址的例子。下面是我们刚才使用的模式(先是一个连续重复 3 次的子表达式,然后是最后一组数字):

\d{1,3}(\.\d{1,3}){3}
在工具中查看
路由器: 192.168.1.1
子网掩码:192.168.255.255
手机:192.168.1.10
电脑:192.168.1.120

这个模式有什么不对的地方吗?从语法上讲,它完全正确。IP 地址由四组数字构成,每组数字由 1 到 3 个数字字符构成,它们之间以英文句号分隔。说这个模式正确,是因为所有合法的 IP 地址都与之相匹配。但深入研究一下就会发现,这个模式还可以匹配其他一些东西;正如我们在 第五章 中说的那样,像"999.999.999.999"这样不合法的 IP 地址也能与之相匹配。

IP 地址由 4 个字节构成,IP 地址中的 4 组数字分别对应着那 4 个字节,所以 IP 地址里的每组数字的取值范围也就是单个字节的表示范围,即 0~255。这意味着 IP 地址里的每一组数字都不能大于 255,可是上面那个模式还能匹配诸如 345、700、999 之类的数字序列,而这些数字在 IP 地址里都是非法的。

有句话希望你能牢牢记住

把必须匹配的情况考虑周全并写出一个匹配结果符合预期的正则表达式很容易,但把不需要匹配的情况也考虑周全并确保它们都将被排除在匹配结果以外往往要困难得多。

如果有办法设定各种取值范围的话,事情会简单得多,但可惜的是正则表达式只是一种工具,而且还是一种不懂数学运算的工具,它们在匹配字符的时候并不真正关心那些字符到底是什么以及有什么含义。你的数学能力再好在这里也帮不上忙。

真的没有解决这个问题的办法吗?未必,只要你们能够充分发挥你们的逻辑思维能力,就能解决与正则表达式有关的任何难题。这里的基本思路是:在构造一个正则表达式的时候,一定要把你想匹配什么和你不想匹配什么详尽地定义清楚。下面是一个合法的 IP 地址里的各组数字必须且只能符合的规则,我们随后将根据这些规则来构造一个相应的模式:

  • ❑ 任何一个 1 位或 2 位数字。
  • ❑ 任何一个以 1 开头的 3 位数字。
  • ❑ 任何一个以 2 开头、第 2 位数字在 0~4 之间的 3 位数字。
  • ❑ 任何一个以 25 开头、第 3 位数字在 0~5 之间的 3 位数字。

像这样把所有的正则全部罗列出来之后,构造一个同时符合所有原则的模式的具体步骤也就清晰了。下面是这个例子的继续:

(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})(\.(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})){3}
在工具中查看
路由器: 192.168.1.1
子网掩码:192.168.255.255
手机:192.168.1.10
电脑:192.168.1.120

这个模式的使用效果显而易见,但它看起来比我们之前使用的 \d{1,3}(\.\d{1,3}){3} 要复杂的多。它和 \d{1,3}(\.\d{1,3}){3} 的构成是一样的, (25[0-5]|2[0-4]\d|1\d{2}|\d{1,2}) 匹配前面一级数字, (\.(25[0-5]|2[0-4]\d|1\d{2}|\d{1,2})){3} 匹配点和后面和一组数字并重复 3 次。

它的构成并不难解理,它真正匹配需要的数字且排除不需要的数字的地方在于 (25[0-5]|2[0-4]\d|1\d{2}|\d{1,2}) ,这部分看起来复杂,但它是由多个子表达式组成,我们只要把它拆解就可以清楚它的含义。

这部分由 25[0-5]2[0-4]1\d{2}\d{1,2} 四个子表达式组成,这四个子表达式刚好对应我们上面分析的 IPV4 的四条规则。

  • 25[0-5] :匹配任何一个以 25 开头、第 3 位数字在 0~5 之间的 3 位数字。
  • 2[0-4] :匹配任何一个以 2 开头、第 2 位数字在 0~4 之间的 3 位数字。
  • 1\d{2} :匹配任何一个以 1 开头的 3 位数字。
  • \d{1,2} :匹配任何一个 1 位或 2 位数字。
该内容基于 《正则表达式必知必会》 二度创作
转载请遵守原作者相关协议并注明本页地址
https://iamhefang.cn/tutorials/正则表达式/第七章-使用子表达式/7.2-子表达式的嵌套