Python / re 正则表达式
Python中经常会用到正则表达式来筛选数据,这里列举一些常用的正则方法仅供参考
先来看一下匹配规则:
常用的匹配规则.jpeg
其实正则表达式不是Python独有的,在其他的编程语言中也可以使用。但是Python的 re
库提供了整个正则表达式的实现,利用这个库,就可以在Python中使用正则表达式。
常用的方法
match()
match() 方法会尝试从字符串的开头匹配字符串,如果匹配成功,就返回结果;如果匹配失败,就返回None ,示例如下:
import re
content = "Hello 987 1233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{2}', content)
print(result)
print(result.group())
print(result.span())
结果如下:
31
<_sre.SRE_Match object; span=(0, 17), match='Hello 987 1233 My'>
Hello 987 1233 My
(0, 17)
说明:
- 这里面用到的匹配模式有 \s : 匹配任意的空白字符 ; \d :匹配任意数字 ;\w:匹配任意的字母、数字、下划线;{n} :匹配 n 个前面的表达式;
- match() 方法中,第一个单数传入正则表达式,第二个参数传入要匹配的字符串
- group() 方法可以输出匹配到的内容
- span() 方法 可以获取到匹配的长度
上面就是用match() 方法来匹配一段文字。但是工作中经常不用这种方式,都是匹配一部分内容,该怎么匹配呢?
-
匹配目标
我们使用正则去匹配内容,怎么提取到我们想要的结果呢?这里我们可以使用()来将我们要提取的部分给括起来,然后调用 group() 方法即可。
示例如下:
import re
content = "Hello 9871233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello.*(\d+).*s$', content)
print(result)
print(result.group(1))
print(result.span())
结果如下:
30
<_sre.SRE_Match object; span=(0, 30), match='Hello 9871233 My name is Kings'>
3
(0, 30)
说明:
- 使用group(n):可以提取第 n 个被()包含的内容
- 如果使用 group() : 获取的是整个内容
-
通用匹配
从上面的例子中我们可以看出,出现数字的地方用了好多\d,有空白我们就用 \s,如果数字和空白很多的话,这种方式就是不可取的了。。这里有一个通用的匹配:就是 .(点星)。.(点)可以代表任何除换行符之外的字符,(星)可以代表前面0个或多个表达式。二者组合,就可以
示例如下:
import re
content = "Hello 987 1233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello.*s$', content)
print(result)
print(result.group())
print(result.span())
结果如下:
31
<_sre.SRE_Match object; span=(0, 31), match='Hello 987 1233 My name is Kings'>
Hello 987 1233 My name is Kings
(0, 31)
说明:
- 使用 匹配模式 $:表示匹配一行字符串的结尾
-
贪婪与非贪婪
使用上述的通用匹配模式有可能提取不到我们想要的结果。看下面的例子:我们想要提取所有的数字!
import re
content = "Hello 9871233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello.*(\d+).*s$', content)
print(result)
print(result.group(1))
print(result.span())
结果如下:
30
<_sre.SRE_Match object; span=(0, 30), match='Hello 9871233 My name is Kings'>
3 (结果就一个数字,而不是一串数字)
(0, 30)
看到结果只有一个数字。。。这是为什么?这里就提到了 贪婪匹配 、非贪婪匹配。
贪婪匹配
:.* (点星)尽可能多的匹配字符串
非贪婪匹配
:.*? (点星问好)尽可能少的匹配字符串
我们现在把 ?(问好) 加进去,看看会发生什么:
import re
content = "Hello 9871233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello.*?(\d+).*s$', content)
print(result)
print(result.group(1))
print(result.span())
结果如下:
30
<_sre.SRE_Match object; span=(0, 30), match='Hello 9871233 My name is Kings'>
9871233
(0, 30)
现在的结果就是我们要想要的了。
说明:
- 如果我们想提取的内容在字符串的结尾,那么我们就不能使用 非贪婪模式了,因为它是尽可能少的获取内容。如果使用,我们可能获取不到结果。
实例如下:
import re
content = "Hello 9871233 My name is Kings"
print(len(content))
# 匹配
result = re.match('^Hello.*?(\d+).*is\s(.*?)', content)
print(result)
print(result.group(2))
print(result.span())
结果如下:
30
<_sre.SRE_Match object; span=(0, 25), match='Hello 9871233 My name is '>
结果为空
(0, 25)
-
修饰符
修饰符有很多,这里只介绍两种,在网页匹配中经常用到的。re.S
、 re.I
re.S : 解决换行匹配问题
re.I :解决大小写问题
示例如下:re.S
import re
content = '''Hello 9871233 My name
is Kings'''
print(len(content))
# 匹配
result = re.match('^Hello.*?(\d+).*is(.*)', content, re.S)
print(result)
print(result.group(2))
print(result.span())
结果如下:
31
<_sre.SRE_Match object; span=(0, 31), match='Hello 9871233 My name \nis Kings'>
Kings
(0, 31)
示例如下:re.I
import re
content = '''Hello 9871233 My name is Kings'''
print(len(content))
# 匹配
# 来个大写字母 O
result = re.match('^HellO.*?(\d+).*is(.*)', content, re.I)
print(result)
print(result.group(2))
print(result.span())
结果如下:
30
<_sre.SRE_Match object; span=(0, 30), match='Hello 9871233 My name is Kings'>
Kings
(0, 30)
-
转义匹配
前面介绍了好多匹配模式,但是,如果目标字符串里面包含匹配模式对应的字符,又该怎么办呢?
这就用到了 转义字符:当遇到特殊字符(正则匹配模式字符)时,在前面加反斜杠\ 转义就行。
实例如下:
import re
content = '(百度)www.wangpai.com?order=123&name=xiaoerlang'
print(len(content))
# 匹配
result = re.match('^\(百度\)www\.wangpai\.com\?order=(.*?)&name=(.*)', content, re.S)
print(result)
print(result.group(1))
print(result.group(2))
结果如下:
45
<_sre.SRE_Match object; span=(0, 45), match='(百度)www.wangpai.com?order=123&name=xiaoerlang'>
123
xiaoerlang
search()
前面我们提到了 match() 方法,只能从字符串开头匹配,如果不从字符串开头匹配怎么办呢?
search() 方法:它会扫描整个字符串,然后返回第一个
成功匹配的结果。如果没有找到结果,就返回None。
示例如下:
import re
html = '''
<div class="pc_temp_songlist pc_rank_songlist_short">
<ul>
<li class=" " title="冷漠、李磊 - 我们想要的" data-index="12">
<span class="pc_temp_btn_check pc_temp_btn_checked" data-index="12"></span>
<span class="pc_temp_coverlayer"></span>
<span class="pc_temp_num">
13
</span>
<span class="pc_temp_tips_l">
<i class="pc_temp_icon_new" title="新入榜"></i>
</span>
<a href="http://www.kugou.com/song/pyaswf9.html" data-active="playDwn" data-index="12" class="pc_temp_songname" title="冷漠、李磊 - 我们想要的" hidefocus="true">冷漠、李磊 - 我们想要的</a>
<span class="pc_temp_tips_r">
<a href="javascript:;" data-active="play" data-index="12" class="pc_temp_btn_listen" title="播放" hidefocus="true">播放</a>
<a href="javascript:;" onclick="_hmt.push(['_trackEvent', 'hidedown', 'hidecilick', 'hidepc']);" data-active="download" data-index="12" class="pc_temp_btn_download" title="下载" hidefocus="true">下载</a>
<a href="javascript:;" data-active="share" data-index="12" class="pc_temp_btn_share" title="分享" hidefocus="true">分享</a>
<span class="pc_temp_time">
3:18
</span>
</span>
</li>
<li class=" " title="蒋雪儿 - 一生等你" data-index="13">
<span class="pc_temp_btn_check pc_temp_btn_checked" data-index="13"></span>
<span class="pc_temp_coverlayer"></span>
<span class="pc_temp_num">
14
</span>
<span class="pc_temp_tips_l">
<i class="pc_temp_icon_new" title="新入榜"></i>
</span>
<a href="http://www.kugou.com/song/rdbvkf5.html" data-active="playDwn" data-index="13" class="pc_temp_songname" title="蒋雪儿 - 一生等你" hidefocus="true">蒋雪儿 - 一生等你</a>
<span class="pc_temp_tips_r">
<a href="javascript:;" data-active="play" data-index="13" class="pc_temp_btn_listen" title="播放" hidefocus="true">播放</a>
<a href="javascript:;" onclick="_hmt.push(['_trackEvent', 'hidedown', 'hidecilick', 'hidepc']);" data-active="download" data-index="13" class="pc_temp_btn_download" title="下载" hidefocus="true">下载</a>
<a href="javascript:;" data-active="share" data-index="13" class="pc_temp_btn_share" title="分享" hidefocus="true">分享</a>
<span class="pc_temp_time">
3:49
</span>
</span>
</li>
</ul>
</div>
'''
result = re.search('<li.*?title=(.*?)\sdata', html, re.S)
print(result.group(1))
结果如下:
"冷漠、李磊 - 我们想要的"
说明:
- search() 方法只返回匹配到的第一个值,想获取所有的信息,就要用到下面的方法。
findall()
该方法在匹配的时候会查找所有的符合规则的内容并返回,如果没有查到就返回None。
仍然用上面的例子:
import re
html = '''
<div class="pc_temp_songlist pc_rank_songlist_short">
<ul>
<li class="lengmo" title="冷漠、李磊 - 我们想要的" data-index="12">
<span class="pc_temp_btn_check pc_temp_btn_checked" data-index="12"></span>
<span class="pc_temp_coverlayer"></span>
<span class="pc_temp_num">
13
</span>
<span class="pc_temp_tips_l">
<i class="pc_temp_icon_new" title="新入榜"></i>
</span>
<a href="http://www.kugou.com/song/pyaswf9.html" data-active="playDwn" data-index="12" class="pc_temp_songname" title="冷漠、李磊 - 我们想要的" hidefocus="true">冷漠、李磊 - 我们想要的</a>
<span class="pc_temp_tips_r">
<a href="javascript:;" data-active="play" data-index="12" class="pc_temp_btn_listen" title="播放" hidefocus="true">播放</a>
<a href="javascript:;" onclick="_hmt.push(['_trackEvent', 'hidedown', 'hidecilick', 'hidepc']);" data-active="download" data-index="12" class="pc_temp_btn_download" title="下载" hidefocus="true">下载</a>
<a href="javascript:;" data-active="share" data-index="12" class="pc_temp_btn_share" title="分享" hidefocus="true">分享</a>
<span class="pc_temp_time">
3:18
</span>
</span>
</li>
<li class="jiangxueer" title="蒋雪儿 - 一生等你" data-index="13">
<span class="pc_temp_btn_check pc_temp_btn_checked" data-index="13"></span>
<span class="pc_temp_coverlayer"></span>
<span class="pc_temp_num">
14
</span>
<span class="pc_temp_tips_l">
<i class="pc_temp_icon_new" title="新入榜"></i>
</span>
<a href="http://www.kugou.com/song/rdbvkf5.html" data-active="playDwn" data-index="13" class="pc_temp_songname" title="蒋雪儿 - 一生等你" hidefocus="true">蒋雪儿 - 一生等你</a>
<span class="pc_temp_tips_r">
<a href="javascript:;" data-active="play" data-index="13" class="pc_temp_btn_listen" title="播放" hidefocus="true">播放</a>
<a href="javascript:;" onclick="_hmt.push(['_trackEvent', 'hidedown', 'hidecilick', 'hidepc']);" data-active="download" data-index="13" class="pc_temp_btn_download" title="下载" hidefocus="true">下载</a>
<a href="javascript:;" data-active="share" data-index="13" class="pc_temp_btn_share" title="分享" hidefocus="true">分享</a>
<span class="pc_temp_time">
3:49
</span>
</span>
</li>
</ul>
</div>
'''
result = re.findall('<li.*?title=(.*?)\sdata', html, re.S)
print(result)
结果如下:
['"冷漠、李磊 - 我们想要的"', '"蒋雪儿 - 一生等你"']
说明:返回的结果是一个列表。
sub()
有时候我们用正则表达式提取信息的时候,会遇到原始文本太长,无用信息太多的情况。就这用到了sub() 方法:通过替换的方式将文本进行精简,比如:去掉某一个标签。
借用上述的例子:
result = re.sub('<span.*?>|</span>|<i.*?>|</i>|<a.*?>|</a>', " ", html)
print(result)
结果如下:
<div class="pc_temp_songlist pc_rank_songlist_short">
<ul>
<li class="lengmo" title="冷漠、李磊 - 我们想要的" data-index="12">
13
冷漠、李磊 - 我们想要的
播放
下载
分享
3:18
</li>
<li class="jiangxueer" title="蒋雪儿 - 一生等你" data-index="13">
14
蒋雪儿 - 一生等你
播放
下载
分享
3:49
</li>
</ul>
</div>
说明:
- 该方法的参数:第一个是正则法则、第二个是要插入的字符、第三个是原始字符串
- 清理数据经常用到
compile()
前面介绍的几种方法,在匹配字符串之前都要先编写匹配规则,如果要处理好多个类似的文本,是不是要写好多个一样的匹配规则呢?
这里介绍一下 compile() 方法,将正则字符串编译成正则表达式对象,一遍在后面的匹配中复用。实例代码如下:
import re
content1 = '2016-12-17 12:00'
content2 = '2017-12-05 12:00'
content3 = '2018-12-25 12:00'
# 将时间去掉
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, " ", content1)
print(result1)
result2 = re.sub(pattern, " ", content2)
print(result2)
result3 = re.sub(pattern, " ", content3)
print(result3)
结果如下:
2016-12-17
2017-12-05
2018-12-25
到此为止,正则表达式的基本用法就介绍完了,后面会通过具体的实例来讲解正则方法,先附上一个demo