浅谈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 相关文章推荐
Windows系统下安装Python的SSH模块教程
Feb 05 Python
sublime python3 输入换行不结束的方法
Apr 19 Python
matplotlib给子图添加图例的方法
Aug 03 Python
Python字典循环添加一键多值的用法实例
Jan 20 Python
python3 selenium自动化 下拉框定位的例子
Aug 23 Python
python实现的发邮件功能示例
Sep 11 Python
使用Python实现分别输出每个数组
Dec 06 Python
Python 3.8 新功能大揭秘【新手必学】
Feb 05 Python
python 已知三条边求三角形的角度案例
Apr 12 Python
Selenium及python实现滚动操作多种方法
Jul 21 Python
浅谈Selenium 控制浏览器的常用方法
Dec 04 Python
python 爬虫爬取京东ps4售卖情况
Dec 18 Python
python中subplot大小的设置步骤
手把手教你实现PyTorch的MNIST数据集
PyMongo 查询数据的实现
Jun 28 #Python
浅谈哪个Python库才最适合做数据可视化
总结Python变量的相关知识
详解非极大值抑制算法之Python实现
Python实现生活常识解答机器人
You might like
php流量统计功能的实现代码
2012/09/29 PHP
PHP判断图片格式的七种方法小结
2013/06/03 PHP
php打开远程文件的方法和风险及解决方法
2013/11/12 PHP
9个比较实用的php代码片段
2016/03/15 PHP
在php的yii2框架中整合hbase库的方法
2018/09/20 PHP
JavaScript的Cookies
2008/01/16 Javascript
Jquery操作Select 简单方便 一个js插件搞定
2009/11/12 Javascript
js超时调用setTimeout和间歇调用setInterval实例分析
2015/01/28 Javascript
jquery实现的树形目录实例
2015/06/26 Javascript
javascript获取系统当前时间的方法
2015/11/19 Javascript
全面解析Bootstrap表单使用方法(表单样式)
2015/11/24 Javascript
学习JavaScript设计模式(单例模式)
2015/11/26 Javascript
jQuery点击其他地方时菜单消失的实现方法
2016/04/22 Javascript
nodejs 搭建简易服务器的图文教程(推荐)
2017/07/18 NodeJs
jQuery实现滚动效果
2017/11/17 jQuery
Vue.js 点击按钮显示/隐藏内容的实例代码
2018/02/08 Javascript
详解vue中组件参数
2018/07/09 Javascript
postman自定义函数实现 时间函数的思路详解
2019/04/17 Javascript
vue实现鼠标移过出现下拉二级菜单功能
2019/12/12 Javascript
详解JavaScript中的this指向问题
2021/02/05 Javascript
[52:52]完美世界DOTA2联赛PWL S3 LBZS vs access 第一场 12.10
2020/12/13 DOTA
Django imgareaselect手动剪切头像实现方法
2015/05/26 Python
微信 用脚本查看是否被微信好友删除
2016/10/28 Python
python数据清洗系列之字符串处理详解
2017/02/12 Python
从django的中间件直接返回请求的方法
2018/05/30 Python
3个用于数据科学的顶级Python库
2018/09/29 Python
nohup后台启动Python脚本,log不刷新的解决方法
2019/01/14 Python
python 实现图片裁剪小工具
2021/02/02 Python
澳大利亚当地社区首选的光学商店:1001 Optical
2019/08/24 全球购物
Aosom西班牙:家具在线商店
2020/06/11 全球购物
Loreto Gallo英国:欧洲领先的在线药房
2021/01/21 全球购物
轻化专业学生实习自我鉴定
2013/09/20 职场文书
车间副主任岗位职责
2013/12/24 职场文书
高级销售求职信
2014/02/21 职场文书
weblogic服务建立数据源连接测试更新mysql驱动包的问题及解决方法
2022/01/22 MySQL
Python循环之while无限迭代
2022/04/30 Python