3.2 多选结构

2018-12-13  本文已影响14人  马小跳_

上一节中用[1-9]\d{14}(\d{2}[\dx])?匹配身份证号,思路是把18位号码中多出的3位“合并”到匹配15位号码的表达式中。这里也可以分情况处理:

情况 表达式
15位身份证 [1-9]\d{14}
18位身份证 [1-9]\d{16}[\dx]

这两种情况只要有一个能匹配,就是合法的身份证号。需要用到括号的另一个功能:多选结构(alternative)。

多选结构的形式是(...|...),在括号内部用竖线|分隔开多个子表达式,这些子表达式也叫做多选分支(option);在一个多选结构内,多选分支的数量没有限制。在匹配时,整个多选结构就视为一个元素,只要其中某个子表达式能够匹配,整个多选结构就匹配成功;如果所有子表达式都不能匹配,则整个多选结构就匹配失败。多个子表达式之间是或的关系。

例3-9 用多选结构匹配身份证

idCardRegex = re.compile(r'^([1-9]\d{14}|[1-9]\d{16}[\dx])$')
print(idCardRegex.search('14112219900111022x'))
print(idCardRegex.search('123451234512345'))

多选结构在实际中经常遇到,比如匹配IP地址:IP地址(暂不考虑ipv6)分为四段,每段都是八位二进制数,换算成常见的是禁止,取值在0~255之间,之间以点号分割。

匹配一段数值在0~255之间的文本,思路如下:

情况 表达式
如果是一位数,那么,对数字没有限制 [0-9]
如果是二位数,那么,对数字没有限制 [0-9]{2}
如果是三位数,有三种情况 1[0-9][0-9]
2[0-4][0-9]
25[0-5]

如果文本符合其中任何一条规则,就可以判断“文本表示的数字在0~255之间”。正则表达式可以写为:^([0-9]|[0-9]{2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$

匹配时间的正则:

时间 表达式
`(0?[1-9] 1[012])`
`(0?[1-9] [12]\d 3[01])`
小时 `(0?\d [01]\d 2[0-4])`
分钟 `(0?\d [1-5]\d 60)`

匹配手机号码:大陆手机号是11位,前三位是号段,到目前为止号段有130~139、150~153、155~156、180、182、185~189,后面8位无限制,再加上开头可能出现的0或+86,正则表达式可以写为:(0|+86)(13[0-9]|15[0-356]|18[025-9])\d{8}

多选结构还可以处理更复杂的问题,比如上一章的tag匹配问题,当时使用的表达式为<[^>]+>,但如果遇到tag内部出现>,比如<input name='xxx' value='>'>。这类问题字符组解决不了,需要用到多选结构。

仔细分析tag中的>之可能作为属性(attribute)出现在单引号字符串和双引号字符串中。根据html规范,引号字符串中不能出现嵌套转义的引号,所以单引号字符串可以用'[^']*'来匹配,双引号字符串可以用"[^"]*"来匹配,相应的,tag中的其他内容可以由[^'"]来匹配。所以最终版tag表达式为<('[^']*'|"[^"]*"|[^'"])+>

注意其中的量词,因为单引号字符串和双引号字符串都可以是空字符串,比如alt=''或alt="",所以匹配其中文本的内容使用*;而[^'"]则没有使用量词,因为它存在于多选结构中,做选结构外部有+限制,保证它不只匹配一个字符。

关于多选结构,最后还要补充三点:

上一篇 下一篇

猜你喜欢

热点阅读