正则表达式子表达式,划分子表达式的目的是为了将其视为单一的实体来使用,子表达式必须出现在字符(
和)
之间。(
和)
是元字符,如果需要匹配(
和)
本身,就必须使用转义字符\(
和\)
。
子表达式进行分组
我们看一个例子,这次用正则表达式来查找IP
地址,IP地址的格式是以英文句号分隔的4组数字,例如12.159.46.200
。因为每组可以包含1~3个数字,所以这4组数字可以统一使用模式\d{1,3}
来匹配(可以参考正则表达式数字),如下所示:
文本
Ping hog.forta.com [12.159.46.200]
with 32 bytes of data:
正则表达式
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
执行结果
在这个例子中,模式\d{1,3}\.
出现了3次,所以可以用重复来表示,下面用子表达式来实现相同的功能
文本
Ping hog.forta.com [12.159.46.200]
with 32 bytes of data:
正则表达式
(\d{1,3}\.){3}\d{1,3}
执行结果
该模式与之前例子有着相同的效果,但我们这次使用了另外一种语法,将表达式\d{1,3}\.
放入(
和)
之中,使其称为一个子表达式。
(\d{1,3}\.){3}
表示该子表达式重复出现3次,随后的\d{1,3}
用来匹配IP地址里的最后一组数字。
在下面的例子里,我们尝试匹配用户记录中的年份:
文本
ID: 042
SEX: M
DOB: 1967-08-17
Status: Active
正则表达式
19|20\d{2}
执行结果
这个例子本要去查找 4 位数的年份1967
,但是结果取差强人意。
原因是模式里的|
是 OR(或)操作符, 19|20
可以匹配 19 或 20, 19|20\d{2}
匹配的是 19 或 20\d{2}
(以20开头的 4 位整数), 最终结果就只匹配到了 19。
正确答案是把 19|20
划分为 子表达式,如下所示:
文本
ID: 042
SEX: M
DOB: 1967-08-17
Status: Active
正则表达式
(19|20)\d{2}
执行结果
子表达式的嵌套
子表达式允许嵌套,事实上,子表达式还可以多重嵌套,一层嵌一层。子表达式嵌套能够构造出功能极其强大的正则表达式,但这难免会让模式变得难以阅读和理解,多少有些让人望而却步。其实大多数嵌套子表达式并没有它们看上去那么复杂。
我们再去看看刚才那么匹配IP地址的例子,我们使用的正则表达式是:
(\d{1,3}\.){3}\d{1,3}
该模式有什么不对的地方吗?IP 地址由 4 个字节构成,形如12.159.46.200
,IP 地址里的每组数字的取值范围是0-255
,也就意味着IP地址里的每一组数字都不能大于 255,可是上面的模式也能匹配 345、700、999 这些无效的 IP 数字。
在构造一个正则表达式的时候,一定要定义清除你想匹配什么,不想匹配什么。一个有效的 IP 地址中每个数字必须符合以下规则:
- 任意的 1 位或 2 位数字。
\d{1,2}
- 任意的以 1 开头的 3 位数字。
1\d{2}
- 任意以 2 开头的,第二位数字在0-4之间的3位数字。
2[0-4]\d
- 任意以25开头的,第三位数字在0-5之间的3位数字。
25[0-5]
当依次罗列出所有规则后,模式该是什么样子就变得一目了然了,如下所示:
文本
Ping hog.forta.com [12.159.46.200]
with 32 bytes of data:
正则表达式
(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))\.){3}(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2})))
执行结果
我们在构造模式的时候,也需要注意它的顺序,如下所示:
文本
Ping hog.forta.com [12.159.46.200]
with 32 bytes of data:
正则表达式
(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5])))
执行结果
这次未能匹配末尾的 0 ,因为模式是从左到右进行评估,所以首先测试第一个,然后测试第二个,以此类推,只要匹配到任何模式,就不再测试选择其他模式了。
极客教程相关文章推荐,欢迎阅读!
正则表达式匹配数字范围
正则表达式回溯法
正则表达式位置匹配
正则表达式重复匹配
正则表达式排除字符
正则表达式元字符