这篇文章上次修改于 607 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
本文章转载至公众号:麦叔编程(回复re即可查看该文章)
正则表达式是爬虫,Web开发,数据处理等各类涉及到文本处理的一把锋利的瑞士军刀,是每个程序员必须掌握的一门技能。本文稍微有点长,但耐心看完,实践其中的例子,你的功力必会更精进一层!
如果你对正则表达式还是小白,强烈建议去B站看我的配套视频,在B站搜“麦叔编程 正则表达式”就可以找到了。
如果你已经有一定基础了,看本文应该就够了!
不管有没有基础,本文最后有我整理的正则表达式语法清单,建议下载保存!
1. 正则表达式的7个境界
假设有一段文字:
text = '身高:178,体重:168,学号:123456,密码:9527'
要确定文本中是否包含数字123456,我们可以用in运算符,也可以使用index函数:
text = '身高:178,体重:168,学号:123456,密码:9527'target = '123456'if target in text: print('找到了')print(text.index(target))
但当问题变得复杂的时候,比如找出字符串中所有数字,用基本的字符串处理就不行了。
这不再是一个固定的字符串匹配问题,而是一个模式,一种规则的匹配。为了解决这个问题,有位叫Stephen的大神在1951年提出了正则表达式。
几乎任何一门通用编程语言都有专门的正则表达式的模块,正则表达式英文是regular expressesion,所以编程语言中的模块名字一般叫re,或者regex等。Python中的正则表达式处理模块是re。
正则表达式就是为了找到符合某种模式的字符串,这些模式包括:是什么字符,重复多少次,在什么位置,有哪些额外的约束。请注意:这里的每一句话都对应了正则表达式中的一类语法。
下面我们通过8个例子,来熟悉正则表达式,后面再讲写正则表达式的套路和正则表达式的语法。
level1 - 固定的字符串
要求:确定字符串中是否有123456
import retext = '麦叔身高:178,体重:168,学号:123456,密码:9527'print(re.findall(r'123456', text))
代码说明:
- 第1行,引入正则表达式模块re
- 第3行,使用re的findall()方法找到所有符合模式的字符串,这里的模式就是123456,也就是说找到字符串中所有的123456。
- findall()方法的第1个参数是模式,第2个参数是要查找的字符串。
- 模式中会有一些特殊字符,所以用r表示这是一个raw字符串,让Python不要去转义里面的特殊字符。
上面程序的运行结果是:[123456],因为整个字符串中就1个123456。
level1就是一个固定的字符串匹配,可以用传统的字符串匹配解决。
level2 - 某一类字符
要求:找出所有的单个的数字
text = '麦叔身高:178,体重:168,学号:123456,密码:9527'print(re.findall(r'\d', text))
这个表达式\d
表示所有的数字,所以1,7,8,1,6,8等都可以匹配到。这是很简单的模式,只匹配1个单独的数字。
如果你完全没有接触过正则表达式,看着有点懵逼,去我看在B站的视频吧,让我手把手教你!
level3 - 重复某一类字符
要求:找所有的数字,比如178,168,123456,9527等。
text = '麦叔身高:178,体重:168,学号:123456,密码:9527'print(re.findall(r'\d+', text))
这个模式\d+
在\d的后面增加了+号,表示数字可以出现1到多次,所以178等都符合它的要求。
leve4 - 组合level2
要求:找出座机号码
text = '麦叔电话是18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166'print(re.findall(r'\d{4}-\d{8}', text))
\d{4}-\d{8}
这是一个组合的模式,表示前面4个数字,中间一个横杠,后面8个数字。
这里会匹配一个结果:0571-52152166
leve5 - 多种情况
要求:找出手机号码或者座机号码
text = '麦叔电话是18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166'print(re.findall(r'\d{4}-\d{8}|1\d{10}', text))
比上面有复杂了点,因为使用竖线(|)来表示”或“的关系,就是手机号码和电话号码都可以。
这里会匹配三个结果:18812345678,18887654321,0571-52152166。
level6 - 限定位置
要求:在句子开头的手机号码,或座机
text = '18812345678,他还有一个电话号码是18887654321,他爱好的数字是01234567891,他的座机是:0571-52152166'print(re.findall(r'^1\d{10}|^\d{4}-\d{8}', text))
在表达式的最开始使用了^符号,表示一定要在句子的开头才行。这时候只有18812345678能匹配上。
level7 - 内部约束
要求:找出形如barbar, dardar的前后三个字母重复的字符串
text = 'barbar carcar harhel'print(re.findall(r'(\w{3})(\1)', text))
这里barbar和carcar会匹配上,但harhel不会被匹配,因为它不是3个字符重复的。
\w{3}表示3个字符,放在小括号中(\w{3})就成为一个分组,而后面的(\1)表示它里面的内容和第1个括号里的内容必须相同,其中的1就表示第1个括号,也就是说3个字符要重复出现两次。
2. 写正则表达式的步骤
如何写正则表达式呢?我总结了几个步骤。不管多复杂,基本上都百试不爽。
我们仍然以包含分机号码的座机电话号码为例,比如0571-88776655-9527,演示下面的步骤:
确定模式包含几个子模式
它包含3个子模式:0571-88776655-9527。这3个子模式用固定字符连接。
各个部分的字符分类是什么
这3个子模式都是数字类型,可以用\d。现在可以写出模式为:
\d-\d-\d
各个子模式如何重复
第1个子模式重复3到4次,因为有010和021等直辖市
第2个子模式重复7到8次,有的地区只有7位电话号码
第3个子模式重复3-4次
加上次数限制后,模式成为:
\d{3,4}-\d{7,8}-\d{3,4}
但有的座机没有分机号,所以我们用或运算符让它支持两者:
\d{3,4}-\d{7,8}-\d{3,4}|\d{3,4}-\d{7,8}
是否有外部位置限制
没有
是否有内部制约关系
没有
经过一通分析,最后的正则就写成了,测试一下:
text = '随机数字:01234567891,座机1:0571-52152166,座机2:0571-52152188-1234'print(re.findall(r'\d{3,4}-\d{7,8}-\d{3,4}|\d{3,4}-\d{7,8}', text))
最后的结果是:两个座机都可以找出来。
3. 语法规则
正则表达式几十个符号,看似很复杂,但如果能否分清楚类别和作用,就没那么复杂了。
- 字符类别表达 - 表达某一类字符,比如数字,字母,3到9之间的任何数字等
- 字符的重复次数,也叫做量词。比如身份证是数字重复15或18次,也就是:\d{15}或者\d{18}。
- 组合模式:把多个简单的模式组合在一起,可以是拼接,也可以是二者选其一。
- 位置:限定模式出现的位置,比如行首,行尾,或者在特定字符之后等。
- 分组,把一个正则表达式分成几个部分,这样可以重复某个分组,或者指定两个分组必须相同等额外的要求。
- 其他:
4. Python正则模块re的用法
python的re模块还比较简单,包括以下几个方法:
- re.search():查找符合模式的字符,只返回第一个,返回Match对象
- re.match():和search一样,但要求必须从字符串开头匹配
- re.findall():返回所有匹配的字符串列表
- re.finditer():返回一个迭代器,其中包含所有的匹配,也就是Match对象
- re.sub():替换匹配的字符串,返回替换完成的文本
- re.subn():替换匹配的字符串,返回替换完成的文本和替换的次数
- re.split():用匹配表达式的字符串做分隔符分割原字符串
- re.compile():把正则表达式编译成一个对象,方便后面使用
5. 更多例子
下面我举了更多的例子,供大家练习和熟悉。
建议先自己尝试去写出相关的正则表达式,再回来看下面的参考答案。
- 匹配Email地址的正则表达式
- 匹配网址URL的正则表达式
- 匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线)
- 匹配国内电话号码(0571-87655322,001-87666622,920-209642-964)
- 匹配腾讯qq号
- 匹配中国邮政编码(6位数字)
- 匹配身份证(15位或18位)
- 匹配ip地址
- 形如"carcar"或"barbar"等会重复的三个字符的单词
==============分隔符==============
现在来看参考答案:
- 匹配Email地址的正则表达式:
\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*
- 匹配网址URL的正则表达式:
[a-zA-z]+://[^s]*
- 匹配帐号是否合法(字母开头,允许5-16字母,允许字母数字下划线):
^[a-zA-Z][a-zA-Z0-9_]{4,15}$
- 匹配国内电话号码,格式为:区号-号码-分机号,分机号可能没有。
d{3,4}-d{7,8}-d{3,4}|d{3,4}-d{7,8}
- 匹配腾讯qq号:
[1-9][0-9]{4,}
- 匹配中国邮政编码(6位数字):
[1-9]\d{5}(?!\d)
- 匹配身份证(15位或18位):
\d{15}|\d{18}
- 匹配ip地址:
\d+.\d+.\d+.\d+
形如"carcar"或"barbar"等会重复的三个字符的单词
(\w{3})(\1)
获取以"密码:"开头的数字:
(?<=密码.)\d+
6. 正则表达式Cheatsheet
建议收藏和下载这个cheatsheet,在必要的时候查询。
如果对你有帮助,请给我点赞,并点在看,谢谢!
只有一条评论 (QwQ)
 ̄﹃ ̄