浅谈Python中的正则表达式


Posted in Python onJune 28, 2021

Python里的正则表达式

Python里的正则表达式,无需下载外部模块,只需要引入自带模块re

import re

官方re模块文档: https://docs.python.org/zh-cn/3.9/library/re.html

同时,Python的正则表达式是PCRE标准的,相较于广泛应用在Unix上的POSIX标准,还是有些区别的(主要是简化)

基本方法

观察re源码,其主要的接口方法有:

  • match(…):从字符串的起始位置匹配一个模式,如果无法匹配成功,则match()就返回none
  • fullmatch(…):是match函数的完全匹配(从字符串开头到结尾)版本
  • search(…):扫描整个字符串并(默认)返回第一个成功的匹配
  • sub(…):用于替换字符串中的匹配项
  • subn(…):和sub(…)类似,但返回值多一个替换次数
  • split(…):分割字符串,返回列表形式f
  • indall(…):在字符串中找到正则表达式所匹配的所有子串,并返回一个列表形式,如果没有找到匹配的,则返回空列表。finditer(…):和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回
  • compile(…):用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用
  • purge(…):用于清除正则表达式缓存

其中,本文主要会介绍的方法为:match(...)search(...)findall(...)spilt(...)。不过,方法都类似,会这些方法,剩下的也大同小异。

元字符与预定义字符集

我认为,元字符算和预定义字符集是正则表达式的核心内容了。

预定义字符集:

预定义字符 说明
\w 匹配下划线“”或任何字母(a-zA-Z)与数字(0-9)等价于a-zA-Z0-9
\W 与\w相反,匹配特殊字符等价于**^a-zA-Z0-9_**
\s 匹配任意的空白字符,等价于**<空格>\r\n\f\v**
\S 与\s相反,匹配任意非空白字符的字符,等价于**^\s**
\d 匹配任意数字,等价于0-9
\D 与\d相反,匹配任意非数字的字符,等价于**^\d**
\b 匹配单词的边界
\B 与\b相反,匹配不出现在单词边界的元素
\A 仅匹配字符串开头,等价于^
\Z 仅匹配字符串结尾,等价于$

元字符:

元字符 说明
. 匹配任何一个字符(除换行符**\n**除外)
^ 脱字符,匹配行的开始
$ 美元符,匹配行的结束
| 连接多个可选元素,匹配表达式中出现的任意子项
[] 字符组,匹配其中的出现的任意一个字符
- 连字符,表示范围,如“1-5”等价于“1、2、3、4、5”
? 匹配其前导元素0次或1次
* 匹配其前导元素0次或多次
+ 匹配其前导元素1次或多次
{n}/{m,n} 匹配其前导元素n次/匹配其前导元素m~n次
() 在模式中划分出子模式,并保存子模式的匹配结果

一般来说,使用+?*{n}{n,}{n,m}时,即激活正则表达式的贪婪模式。可以在其后加入?来取消贪婪模式。

贪婪模式

一般来见,重复多次匹配就是贪婪模式,也就是尽可能匹配多个字符。

比如:

import re

lineOne = "Who is the Mintimate"
# 贪婪模式
print(re.findall(r'\w+',lineOne))
# 非贪婪模式
print(re.findall(r'\w',lineOne))
print(re.findall(r'\w+?',lineOne))

输出:

['Who', 'is', 'the', 'Mintimate']
['W', 'h', 'o', 'i', 's', 't', 'h', 'e', 'M', 'i', 'n', 't', 'i', 'm', 'a', 't', 'e']
['W', 'h', 'o', 'i', 's', 't', 'h', 'e', 'M', 'i', 'n', 't', 'i', 'm', 'a', 't', 'e']

可以看到,使用**?**来激活非贪婪模式,基本是让多次匹配无效化。

捕获与非捕获括号

之所以捕获与非捕获括号单独出来讲,其实是我当时学习正则时候,这边卡了很久。

  • 捕获括号:()
  • 非捕获括号:(?:)

捕获括号其实就是代码里的优先级一样,比如:

2*(2+3)=10

之所以,我们会先算2+3,是因为有**()的存在。正则里也是,如果存在()**,则会优先捕获()内的内容:

import re

lineOne = "Who is Mintimate?"
# 未使用捕获括号
print(re.findall(r'Mintimate',lineOne))
# 使用捕获括号
print(re.findall(r'M(intimate)',lineOne))
# 使用非捕获括号
print(re.findall(r'M(?:intimate)',lineOne))

输出结果:

['Mintimate']
['intimate']
['Mintimate']

而非捕获括号主要与|同时使用:

import re

lineOne = "This is the Mintimate,not the Minimen?"
print(re.findall(r'M(?:intimate|inimen)',lineOne))

输出结果:

['Mintimate', 'Minimen']

正则匹配(判断目标格式)

主要讲解Python下的几个方法使用方法。

match匹配

match(…)即:

re.match(pattern, string, flags=0)

参数的具体含义如下:

  • pattern:表示需要传入的正则表达式。
  • string:表示待匹配的目标文本。
  • flags:表示使用的匹配模式。如:是否区分大小写,多行匹配等等。可省略,默认为0

使用match进行正则匹配,可以方便我们对字符串内类型的判断,如:是否为纯数字或第一位数否为数字

import re

lineOne = "7704194"
lineTwo = "My UID in Tencent Community is:7704194"
print(re.match(r"\d", lineOne))
print(re.match(r"\d+", lineOne))
print("===")
print(re.match(r"\d", lineTwo))
print(re.match(r"\d+", lineTwo))

输出结果:

<re.Match object; span=(0, 1), match='7'>
<re.Match object; span=(0, 7), match='7704194'>
===
None
None

其中,\d为匹配0-9的数字类型,而+是匹配出现1次或多次。

正则搜索(提取/分组字符)

正则搜索,常用的是search和findall方法了,方法体均一样:

re.search(pattern, string, flags=0)
re.findall(pattern, string, flags=0)

search和march类似,均是匹配字符串内容,不符合返回None。但是主要区别:

  • re.match() 从第一个字符开始找, 如果第一个字符就不匹配就返回None, 不继续匹配. 用于判断字符串开头或整个字符串是否匹配,速度快
  • re.search() 会整个字符串查找,直到找到一个匹配

代码中更形象:

import re

lineOne = "7704194"
lineTwo = "My UID in Tencent Community is:7704194"
# 使用match搜索纯数字字符串
print(re.match(r"\d", lineOne))
# 使用search搜索纯数字字符串
print(re.search(r"\d", lineOne))
# 使用match搜索复合字符串
print(re.match(r"\d", lineTwo))
# 使用search搜索复合字符串
print(re.search(r"\d", lineTwo))

其输出结果:

<re.Match object; span=(0, 1), match='7'>
<re.Match object; span=(0, 1), match='7'>
None
<re.Match object; span=(31, 32), match='7'>

而findall,在上match和search的前提下,进一步封装。相对于强化版的match和search

import re

lineOne = "7704194"
lineTwo = "My UID in Tencent Community is:7704194"
print(re.findall(r'\d',lineOne))
print(re.findall(r"\d",lineTwo))

输出结果:

['7', '7', '0', '4', '1', '9', '4']
['7', '7', '0', '4', '1', '9', '4']

而如果你想完成提取:

print(re.findall(r"\d+",lineTwo))

输出:

['7704194']

方便在数据处理时,快速提取连续数字?( ̄? ̄"")?。

操作实例

单单看文档,总是不实际。这边我演示几个正则表达式的实例(我根据我自己使用环境所写,可能在其他特殊环境有问题

URL去参

在写爬虫时候,有时候得到的URL是带标签(#)或者Get请求(?id=*)的,但是有时候我们需要去除这些参数,得到纯净的URL地址,这个时候可以用正则表达式:

lineOne = "https://www.mintimate.cn#mintimate"
lineTwo = "https://www.mintimate.cn?user=mintimate"
print(re.findall(r'https?://(?:[\w]|[/\.])*',lineOne))
print(re.findall(r'https?://(?:[\w]|[/\.])*',lineTwo))

效果:

['https://www.mintimate.cn']
['https://www.mintimate.cn']

这里主要的细节:

  • https?:匹配http或https
  • (??:非捕获括号,用于和后续|进行配合

IPv4匹配

用正则匹配IPv4就比较复杂了,我是这样写的:

import re

lineOne = "192.168.1.1"
lineTwo="这不是IPv4嗷"
isIPv4=re.compile(r'((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}')
print(isIPv4.search(lineOne))
print(isIPv4.search(lineTwo))

输出结果为:

<re.Match object; span=(0, 11), match='192.168.1.1'>
None

解释一下:

  • 末尾的{3},代表前面(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2}))重复三次匹配,
  • 而前面的((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})我们可以拆分为两部分,(2(5[0-5]|[0-4]\d))和0-1?\d{1,2}:前者是匹配首位为2开头、第二位为1到5或1到4、最后一位为0到9;后者是匹配第一位为0或1,且?代表可以不存在这一项,后两位为两位0-9的数字。

效率问题

使用正则表达式,很大程度是为了精简代码,但是存在一下问题:

  • 代码可读性降低:普通的匹配数字还好,但是如果都像IPv4这样的,一定程度可读性就降低了,维护成本高(虽然后期一般不回去改)
  • 解析时间长:这个还是要看具体代码,但是总的来说:贪婪模式相比懒惰模式以及独占模式有一个回溯过程,消耗资源会更多。

解决方案:

  • 一条正则表达式规则如果运用上百次,可以使用compile()方法进行预先加载。
  • 减少使用贪婪模式。

总结

正则表达式是一个很重要的工具,尤其是在Python数据处理时,能高效处理问题事件。看完这篇文章后,应该对正则表达式不在陌生,感兴趣可以自己写个正则规则,如:强密码判断、IPv6的判断等

另外,因为篇幅所限,更多Python内的细则,可以参考官方文档:

https://docs.python.org/zh-cn/3.9/library/re.html

到此这篇关于浅谈Python中的正则表达式的文章就介绍到这了,更多相关Python正则表达式内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python random模块(获取随机数)常用方法和使用例子
May 13 Python
用Python实现一个简单的线程池
Apr 07 Python
python函数装饰器用法实例详解
Jun 04 Python
Python实现Linux中的du命令
Jun 12 Python
Python利用字典将两个通讯录文本合并为一个文本实例
Jan 16 Python
解决python3 安装完Pycurl在import pycurl时报错的问题
Oct 15 Python
Python3.5 Pandas模块之DataFrame用法实例分析
Apr 23 Python
利用python开发app实战的方法
Jul 09 Python
python实现截取屏幕保存文件,删除N天前截图的例子
Aug 27 Python
python FTP批量下载/删除/上传实例
Dec 22 Python
Window系统下Python如何安装OpenCV库
Mar 05 Python
Python分类测试代码实例汇总
Jul 23 Python
python中subplot大小的设置步骤
手把手教你实现PyTorch的MNIST数据集
PyMongo 查询数据的实现
Jun 28 #Python
浅谈哪个Python库才最适合做数据可视化
总结Python变量的相关知识
详解非极大值抑制算法之Python实现
Python实现生活常识解答机器人
You might like
PHP 彩色文字实现代码
2009/06/29 PHP
PHP连接数据库实现注册页面的增删改查操作
2016/03/27 PHP
用 javascript 实现的点击复制代码
2007/03/24 Javascript
iframe 异步加载技术及性能分析
2011/07/19 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
2012/12/27 Javascript
关于jquery.validate1.9.0前台验证的使用介绍
2013/04/26 Javascript
JS定时器实例详细分析
2013/10/11 Javascript
javascript移动设备Web开发中对touch事件的封装实例
2014/06/05 Javascript
js实现编辑div节点名称的方法
2014/12/17 Javascript
微信小程序 图片边框解决方法
2017/01/16 Javascript
jQuery插件HighCharts绘制的基本折线图效果示例【附demo源码下载】
2017/03/07 Javascript
js实现悬浮窗效果(支持拖动)
2017/03/09 Javascript
详解如何用webpack4从零开始构建react开发环境
2019/01/27 Javascript
js tab栏切换代码实例解析
2019/09/03 Javascript
layui table数据修改的回显方法
2019/09/04 Javascript
jquery弹窗时禁止body滚动条滚动的例子
2019/09/21 jQuery
浅谈v-for 和 v-if 并用时筛选条件方法
2019/11/07 Javascript
python sys.argv[]用法实例详解
2018/05/25 Python
python实现彩票系统
2020/06/28 Python
Python实现购物评论文本情感分析操作【基于中文文本挖掘库snownlp】
2018/08/07 Python
pandas 根据列的值选取所有行的示例
2018/11/07 Python
浅谈Python 列表字典赋值的陷阱
2019/01/20 Python
python3.6下Numpy库下载与安装图文教程
2019/04/02 Python
python3.4+pycharm 环境安装及使用方法
2019/06/13 Python
pytz格式化北京时间多出6分钟问题的解决方法
2019/06/21 Python
Python Tornado实现WEB服务器Socket服务器共存并实现交互的方法
2020/05/26 Python
Python可视化工具如何实现动态图表
2020/10/23 Python
Adobe Html5 Extension开发初体验图文教程
2017/11/14 HTML / CSS
黄色火烈鸟:De Gele Flamingo
2019/03/18 全球购物
平面设计岗位职责
2013/12/14 职场文书
测控技术与仪器个人求职信范文
2013/12/30 职场文书
市优秀教师事迹材料
2014/02/05 职场文书
学校领导班子四风问题整改意见
2014/10/02 职场文书
安全月宣传标语
2014/10/07 职场文书
初中毕业感言300字
2015/07/31 职场文书
解析原生JS getComputedStyle
2021/05/25 Javascript