本篇介绍正则匹配规则与如何在python中利用Re模块进行正则匹配。
概念
re模块和正则表达式的关系
正则表达式 和 re 模块没有关系
有了re模块就可以在python语言中操作正则表达式
re 模块本身不提供规则,它只是能让python可以使用正则表达式
什么是正则表达式?
一套规则,用来匹配字符串
能做什么?
检测一个输入的字符串是否合法(场景1)(web开发项目 表单验证)
用户输入一个内容的时候,我们要提前做检测,这样能提高程序的效率和减少服务器的压力
从一个大文件当中找到所有符合规则的内容(场景2)(日志分析,爬虫)
能够高效的从一大段文字中快速找到符合规则的内容。
这两个场景的差别在于:
- 场景一,我们常用^ $ 限制字符串为想要的内容;场景二,要尽可能匹配符合规则地字符串。
正则规则
所有的规则中的字符就可以刚好匹配到字符串的内容
正则规则-第一部分
字符组[]
字符组:描述的是一个位置上能出现的所有可能性
接受范围:可以描述多个范围,连着写就行
[abc] 一个中括号只表示一个字符位置
意思是匹配a或b或c
[匹配一个数字]
- [0-9] 根据ASCII码进行范围的比对
- (0的ascii到9的ascii之间的所有;这个范围只能从小到大) 如[0-7]可以 但[7-0]不行
- [a-zA-z] 表示大小写
- 记忆:
1
2A 65 - Z 90 a 97 - z 122
中文的 unicode 编码范围 主要在 [\u4e00-\u9fa5]
元字符
元字符:在正则表达式中能够帮助我们表示匹配的内容的符号
1 | 铺垫: |
注意:
- 如果匹配成功:光标移动到匹配成功的最后一个字符
- 如果匹配失败,就从匹配开始字符的下一个字符开始
- 例子
1 | print(re.findall('a.b','aaab')) # ['aab'] |
量词
量词 :必须跟在元字符后面,只能约束前面元字符的出现的次数
1 | {n} 表示匹配n次 |
1 | 练习: 匹配手机号码 |
贪婪匹配
1 | 贪婪匹配 ---> 往右走是贪心算法,往左返回是回溯算法 |
转义符
1 | 原本有特殊意义地字符,到了表达她本身地意义地时候,需要转义 |
小结:
1 |
|
练习
1 | 匹配18/15位地身份证号 |
Re模块
1 | import re |
findall
以列表的形式返回匹配成功的文本
如果我们要查找的内容在一个复杂的环境中,我们要查的内容并没有一个突出的,与众不同的特点,甚至会和不需要的杂乱数据混合在一起,这个时候我们就需要把所有的数据都统计出来,然后对这个数据进行筛选,把我们真正需要的数据对应的正则表达式用()圈起来,这样我们就可以筛选出来想要的东西。(?:可以不让它优先显示)
1 | > import re |
search
search 只取第一个符合条件的,没有优先显示这件事儿
- 还是按照完整的正则进行匹配,显示匹配到第一个内容,但是我们可以通过group方法传参数
- 变量.group()的结果 完全和 变量.group(0)的结果一致
1 | 'a', 'ba') r = re.match( |
match
相当于在\d+ 前面人为的加上^ , 除此之外和search一摸一样。
1 | ret4 = re.match('\d+','小白123小黑456') |
没有match也可以,是用search 正则中’^\d+’
应用场景: 用户输入的内容匹配的时候,要求用户输入11位手机号码,^手机号码正则$
match与search的态度/思路不同:
- match 用来规定这个字符串必须是怎么样的。
- search 用来寻找这个字符串中符合规则的子串。
group
从match/search
返回的正则对象提取结果
。
1 | 'a(b)','ab').group() # () 括号是特别的标示,不会影响正则匹配 re.match( |
split
切割字符串,返回数组
1 | ret = re.split('\d+','小白222xiaohong') |
问题:字符串也有切割,但字符串不提供保留切掉的内容,从逻辑的角度想想为什么它会什么是这样?
sub
替换
1 | ret3 = re.sub('\d+','H','小白123xiaohong456',1) |
subn
1 | ret3 = re.subn('\d+','H','小白123xiaohong456') |
解决效率问题
compile
compile —— 节省代码时间的工具
背景:当我们重复使用一个正则表达式的时候,我们可以利用compile对正则表达式进行编译。使用compile后,节省了多次解析同一个正则表达式的时间。
1 | reg = re.compile('\d+') |
finditer
finditer —— 节省空间
背景:从大文件中找子串,结果特别多。这样找到的结果越多越占用内存 所以我们把返回的列表改成一个迭代器。
1 | ret = re.finditer('\d+','fosaidj234ij') |
compile
与 finditer
组合使用
1 | reg = re.compile('\d+') |
分组命名
分组命名 (?P<名字>正则)
ret.group('名字')
分组命名的引用 (?P=名字)
1 | import re |
分组的索引去引用
1 | print(re.search(r'<(\w+)>.*?</\1>','<abc>sdiofjosaj</abc>')) |
断言
待补充!!!
结论
findall
和search
可以解决80%的问题。有的时候要匹配的内容是包含在不想要的内容之中的,这种情况先把不想要的匹配匹配出来,然后再想办法从结果中去掉。