断言概述与分类
断言是正则中的比较强大用法,并不是所有语言中的正则支持断言,当然python中是支持的
断言氛围下面的几种情况:
- 先行断言 (lookahead assertion)
- 反向先行断言 (negative lookahead assertion)
- 后行断言 ( positive lookbehind assertion)
- 反向后行断言 (negative lookbehind assertion)
接下来咱们分别简单说明下每种情况的使用
先行断言
断言格式: 字符串(?=...)
判断字符串后面必须跟着... ,这里...表示正则也可以表示是普通字符串,可以叫做断言字符串或者断言正则。说起来可能比较费事,我们用示例去演示
import re
# 匹配字符串abc 且断言abc后面必须跟着123,
# 断言字符规则不消耗匹配,也就是下面的匹配仅仅匹配到abc
re.search(r'abc(?=123)','abc123') # 匹配命中 返回abc
re.search(r'abc(?=123)','abc456') # 匹配失败,abc后面没有跟着123
反向先行断言
断言格式: 字符串(?!...)
判断字符串后面必须不可以跟着... ,这里...表示正则也可以表示是普通字符串,可以叫做断言字符串或者断言正则。说起来可能比较费事,我们用示例去演示
import re
# 匹配abc 且abc后面不能跟着123
re.search(r'abc(?!123)','abc123') # 匹配失败,abc后面是123
re.search(r'abc(?!123)','abc456') # 匹配成功,abc后面跟着123
后行断言
断言格式: 字符串(?<=...)
判断字符串前面必须跟着... ,这里...表示正则也可以表示是普通字符串,可以叫做断言字符串或者断言正则。说起来可能比较费事,我们用示例去演示
import re
# 匹配abc,且abc前面必须是一个数字
re.search(r'(?<=\d)abc','6abc') # 匹配成功 abc前面是数字
re.search(r'(?<=\d)abc','_abc') # 匹配失败 abc前面不是数字
反向后行断言
断言格式: 字符串(?!=...)
判断字符串前面必须不可以跟着... ,这里...表示正则也可以表示是普通字符串,可以叫做断言字符串或者断言正则。说起来可能比较费事,我们用示例去演示
import re
# 匹配 abc ,且abc前面必须不能是数字
re.search(r'(?<!\d)abc','_abc') # 匹配成功,abc前不是数字
re.search(r'(?<!\d)abc','6abc') # 匹配失败 abc前是数字
先行后行理解[兵马未动,粮草先行]
配合图理解下面的文字
执行断言是在扫描字符串位置前还是后,如果在扫描位置前叫做先行,如果是后面那就是后行
abc(?=123)
从左到右开始扫描到C的位置发现abc,断言在扫描位置前面,先行断言
(?<=#)abc
从左到右开始扫描扫描到C的位置发现了abc,开始断言,断言在扫描位置后面,后行断言
-
正则表达式扫描是从字符串开始到结尾逐步扫描
-
扫描时候有两个个游标,执行断言前 断言游标与扫描游标在同一个位置,执行断言时候会移动断言游标进行断言,断言接收后归为与扫描游标仍然保持一致
断言案例
密码强度校验,要求密码包含特殊字符【数字键盘0~9上面的字符】,数字,字母区分大小写,密码长度至少8位最多16位
import re
# 注意 这里面巧妙了运用了 先行断言来实现的
#1. 保证字符串匹配8~16个字符
re.search(r'.{8,16}','1aga')
#2. 要求字符串包含特殊字符
re.search(r'(?=.*[!@#$%^&*()]).{8,16}','1aga#$aaa')
#3. 要求字符包含数字
re.search(r'(?=.*[!@#$%^&*()])(?=.*\d).{8,16}','aga#$aaa6')
#4. 必须有大小写字母
re.search(r'(?=.*[!@#$%^&*()])(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16}','aga#$aaa6')
#保证字符必须是8~16个以内 ^$ 界定符保证长度
re.search(r'^(?=.*[!@#$%^&*()])(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16}$','aga#$aaa6Aag')