正则表达式

re模块的快速使用

# 导入re模块
import re

# 使用match方法进行匹配操作
result = re.match(正则表达式,要匹配的字符串)

# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()

re.match是用来进行正则匹配检查的方法,若字符串匹配正则表达式,则match方法返回匹配对象(Match Object),否则返回None(注意不是空字符串"")。

匹配对象Macth Object具有group方法,用来返回字符串的匹配部分。

匹配以itcast开头的语句

import re
result = re.match("itcast","itcast.cn")
result # <_sre.SRE_Match object; span=(0, 6), match='itcast'>
result.group() # itcast

注意:match只能匹配以xxx开头的字符串,而不能匹配xxx位于中间的字符串格式。但是我们可以使用分组的方法,到时候通过分组序号引用想要的内容(见python贪婪和非贪婪案例)

表示字符

在上一小节中,了解到通过re模块能够完成使用正则表达式来匹配字符串

本小节,将要讲解正则表达式的单字符匹配

字符 功能
. 匹配任意1个字符(除了\n)
[ ] 匹配[ ]中列举的字符
\d digit。匹配数字,即0-9。 等价于[0-9]
\D 匹配非数字,即不是数字。 等价于[^0-9]
\s 匹配空白,即 空格,tab键,换行\n
\S 匹配非空白
\w word。匹配单词字符,即a-z、A-Z、0-9、_ 。等价于[a-zA-Z0-9_]
\W 匹配非单词字符。 等价于[^a-zA-Z0-9_]
>>> re.match('\w','9as')
<_sre.SRE_Match object; span=(0, 1), match='9'>
>>> re.match('\w','_as')
<_sre.SRE_Match object; span=(0, 1), match='_'>
>>> re.match('\w','+as')
>>> None

表示数量

匹配多个字符的相关格式

字符 功能
* 匹配前一个字符出现0次或者无限次,即可有可无。 >=0
+ 匹配前一个字符出现1次或者无限次,即至少有1次。 >=1
? 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m} 匹配前一个字符出现m次
{m,} 匹配前一个字符至少出现m次
{m,n} 匹配前一个字符出现从m到n次

可以用括号将多个字符当成一个字符来匹配。事实上使用括号就变成了一个group。

>>> re.match('(123){2}','123123789')
<_sre.SRE_Match object; span=(0, 6), match='123123'>
>>> re.match('(123){2}','123123789').group(1)
'123'
>>> re.match('123{2}','123123')
>>> None
>>> re.match('123{2}','1233123')
<_sre.SRE_Match object; span=(0, 4), match='1233'>

表示边界

字符 功能
^ 匹配字符串开头,因此必须写在开头
$ 匹配字符串结尾,因此必须写在结尾
\b 匹配一个单词的边界
\B 匹配非单词边界

匹配分组

字符 功能
| 匹配左右任意一个表达式
(ab) 将括号中字符作为一个分组
\num 引用分组num匹配到的字符串
(?P<name>) 分组起别名
(?P=name) 引用别名为name分组匹配到的字符串

1.匹配出0-100之间的数字

ret = re.match("[1-9]?\d$|100","78")
ret.group()

2.匹配html标签里的文本

>>> result = re.match(r"<h1>(.*)</h1>","<h1>我爱python</h1>")
>>> result.group()  # 等价于 result.group(0)
'<h1>我爱python</h1>'
>>> result.group(1)  # 引用第一个分组
'我爱python'

3.\num的用法

>>> result = re.match(r"<(.*)><(.*)>.*</\2></\1>","<html><h1>我爱python</h1></html>")
>>> result.group()
'<html><h1>我爱python</h1></html>'
>>> result.group(1)
'html'

4.(?P<name>)的使用

>>> result = re.match(r"<h1>(?P<text>.*)</h1>","<h1>我爱python</h1>")
>>> result
<_sre.SRE_Match object; span=(0, 17), match='<h1>我爱python</h1>'>
>>> result.group('text')
'我爱python'

5.(?P=name)的使用

>>> result = re.match(r"<(?P<key1>.*)><(?P<key2>.*)>.*</(?P=key2)></(?P=key1)>","<html><h1>我爱python</h1></html>")
>>> result.group()
'<html><h1>我爱python</h1></html>'
>>> result.group(1)
'html'

原始字符串

补充:print打印输出时会对字符串中的\进行转义。但是字符串本质上还是带有\。如果字符串前面带有r,则可以避免转义。

>>> mm = "c:\\a\\b\\c"
>>> mm
'c:\\a\\b\\c'
>>> print(mm)
c:\a\b\c
>>> print(r"c:\\a\\b\\c")
c:\\a\\b\\c
>>> print(mm)
c:\a\b\c
>>> r"c:\\a\\b\\c"
'c:\\\\a\\\\b\\\\c'  
>>> re.match("c:\\\\",mm).group()
'c:\\'
>>> ret = re.match("c:\\\\",mm).group()
>>> print(ret)
c:\
>>> ret = re.match("c:\\\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\a",mm).group()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>>

说明

Python中字符串前面加上 r 表示原生字符串

与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。

Python里的原生字符串很好地解决了这个问题,有了原始字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

>>> ret = re.match(r"c:\\a",mm).group()
>>> ret
'c:\\a'
>>> print(ret)
c:\a

re模块的高级用法

search,匹配到第一个就返回,不关心后面有没有满足规则的

需求:匹配出文章阅读的次数

>>> import re
>>> 
>>> ret = re.search(r"\d+", "阅读次数为 9999")
>>> ret.group()
'9999'

findall

需求:统计出python、c、c++相应文章阅读的次数

import re
ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)  # 返回列表,不需要使用group

运行结果:

['9999', '7890', '12345']

sub 将匹配到的数据进行替换,默认匹配所有满足规则的

>>> ret = re.sub(r"\d+", '998', "python = 997 java = 200")
>>> ret
'python = 998 java = 998'

需求:从下面的字符串中取出文本

<div>
        <p>岗位职责:</p>
<p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
<p><br></p>
<p>必备要求:</p>
<p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
<p>&nbsp;<br></p>
<p>技术要求:</p>
<p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
<p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
<p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
<p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
<p>&nbsp;<br></p>
<p>加分项:</p>
<p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>

        </div>
re.sub(r"</?\w+>","",s)

split 根据匹配进行切割字符串,并返回一个列表

需求:切割字符串“info:xiaoZhang 33 shandong”

>>> ret = re.split(r":| ","info:xiaoZhang 33 shandong")
>>> ret
['info', 'xiaoZhang', '33', 'shandong']

python贪婪和非贪婪

Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;

非贪婪则相反,总是尝试匹配尽可能少的字符。

在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。

>>> s="This is a number 234-235-22-423"
>>> r=re.match(".+(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'4-235-22-423'
>>> r=re.match(".+?(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'234-235-22-423'
>>>

正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在我们上面的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。

解决方式:非贪婪操作符“?”,这个操作符可以用在"*","+","?"的后面,要求正则匹配的越少越好。

注意:必须满足其他条件之后才去考虑非贪婪模式

>>> re.match(r"aa(\d+)","aa2343ddd").group(1)
'2343'
>>> re.match(r"aa(\d+?)","aa2343ddd").group(1)
'2'
>>> re.match(r"aa(\d+)ddd","aa2343ddd").group(1) 
'2343'
>>> re.match(r"aa(\d+?)ddd","aa2343ddd").group(1)
'2343'
>>>

练一练,字符串为:

<img data-original="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg" src="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg" style="display: inline;">

请提取url地址

>>> re.findall(r"https.+?\.jpg",s)
['https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg', 'https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg']
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容