正则表达式(re模块)
正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,在文本处理方面功能非常强大,也经常用作爬虫,来爬取特定内容,Python本身不支持正则,但是通过导入re模块,Python也能用正则表达式,正则表达式默认以单行开始匹配的
在线测试:
. | 匹配任意字符,换行符‘\n’除外 |
\ | 转义字符 |
[…] | 字符集类,对应位置可以是集中任意字符,[abcde]==[a-e],[^abcd]表示不是集中的任意一个,特殊符号前要加\ |
\d | 数字[0-9] |
\D | 非数字 |
\s | 空白字符[空格、\t、\r、\n、\f、\v] |
\S | 非空白字符 |
\w | 单词字符[A-Za-z0-9] |
\W | 非单词字符 |
* | 匹配字符0次或无数次 |
+ | 1次或无数次 |
? | 0次或1次 |
{m} | m次 |
{m,n} | m到n次 |
*? {m,n}? | 使匹配变成非贪婪模式 |
^ | 匹配开头,在多行模式中匹配每一行开头 |
$ | 匹配结尾 |
\A | 仅匹配字符串开头 |
\Z | 仅字符串结尾 |
\b | 匹配\w和\W之间,a\b!bcàa!bc |
\B | [^\b] , a\B\bcàabc |
| | 匹配左右任意一个,先左后右,左成功则跳过右, 若没有被包括在()内,范围是整个表达式, |
(…) | 被括起来的内容作为分组 |
1. re.split()分隔符
import re
ss='adb4kss4siko n4bkd4g e5kop'
bb=re.split('4|5',ss)
print(bb)
#返回 ['adb', 'ks s', 'siko n', 'bkd', 'g e', 'kop']
2. re.match方法
尝试从字符串的起始位置开始匹配,若起始位置匹配不成功的话,返回none
^匹配开头,$匹配结尾
1>
import re
content='hello 4654332 gre 4532 bkios igb fs423ge aaa'
result=re.match('^hello.*aaa$',content) # .*范匹配,^匹配开头,$匹配结尾print(result.group())#返回结果hello 4654332 gre 4532 bkios igb fs423ge aaa
***********************************************
result=re.match('^hello\s(\d+)\s.*aaa$',content)
print(result.group(1))#返回4654332,无1返回全部,1表示第一个()匹配的内容print(result.span(1)) #返回 (6, 13) ,无1返回(0,44)
2> 贪婪匹配
使用‘.*’ 尽可能匹配多的字符
import re
content='hello 465789 gre 4532 bkios igb fsge aaa'
result=re.match('^hello.*(\d+).*aaa$',content)
priont(result.group(1)) #返回2,‘.*’多匹配,(\d)只剩最后的2
3> 非贪婪模式
import re
content='hello 465789 gre 4532 bkios igb fsge aaa'
result=re.match('^h.*?(\d+).*aa$',content) #465789, ‘.*’尽可能少的匹配
result=re.match('^h.*?(\w+).*aa$',content) #ello,除下h头,匹配直到不符条件
3. ’.*‘默认匹配不到换行符 ,re.S用来匹配\n等
import re
content='''hello525435
world_isnkgeghgfn $5bg'''
result=re.match('^he.*?\$5bg$',content,re.S) #$需用\转义
print(result.group()) #正常返回并带有换行,去除re.S则失败
************************************************
\s匹配空格,\s*匹配空格与换行
strip消除字符串两边空格
4. re.search方法
扫描整个字符串并返回第一个成功的匹配
import re
content ='Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result =re.search('Hello.*?(\d+).*?Demo',content)
print(result.group())
#返回Hello 1234567 World_This is a Regex Demo
5. re.sub方法
替换字符串中每一个匹配的字串后,返回替换后的字符串
import re
content ='abcdcdef'
result =re.sub('ef','cd',content)
print(result) #返回abcdcdcd
result =re.subn('ef','cd',content)
print(result) #返回('abcdcdcd', 1),替换次数
6. re.compile方法
把字符串编译成正则表达式对象,将一个正则表达式串编译成正则对象,以便于复用该匹配模式
import re
content='''hello1234556 word jgmnlg
is a freestyle'''
pattern=re.compile('hello.*tyle',re.S)
result=re.match(pattern,content)
print(result.group())
7. re.findall方法
搜索字符串,以列表形式返回全部符合条件的匹配到的字符串
8. 应用实例
import re
html = '''<div id='songs-list'>
<h2>经典老歌</h2>
<p>
经典老歌列表
</p>
<ul id='list'>
<li data-view='2'>一路上有你</li>
<li data-view='7'>
<a href='/2.mp3' singer='任贤齐'>沧海一声笑</a>
</li>
<li data-view='4'>
<a href='/3.mp3' singer='齐秦'>往事随风</a>
</li>
<li data-view='6'><a href='/4.mp3' singer='beyond'>光辉岁月</a></li>
<li data-view='5'><a href='/5.mp3' singer='陈慧琳'>记事本</a></li>
<li data-view='5'>
<a href='/6.mp3' singer='邓丽君'><iclass='fa fa-user'></i>但愿人长久</a>
</li>
</ul>
</div>'''
result=re.search("<li.*?active.*?f=\'(.*?)\'\ssinger='(.*?)'>(.*?).*?</li>",html,re.S)
print(result.group(1))
print(result.group(2))
print(result.group(3)) #返回结果:/3.mp3 和 齐秦 (.*?).*?,group(3)被覆盖
#-->result=re.search('<li.*?f=\'(.*?)\'.*?r=\'(.*?)\'>(.*?)</a>',html,re.S)
#返回 /2.mp3 任贤齐 沧海一声笑
#-->去掉re.S,返回/4.mp3 beyond 光辉岁月(re.search匹配成功)
*re.findall
results = re.findall("<li.*?href='(.*?)'.*?singer='(.*?)'>(.*?)</a>",html,re.S)
for result in results: #列表中嵌套元组
print(result)#返回元组
results =re.findall("<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>",html,re.S)
for result in results:
print(result)
9. 原生字符串
import re
#“\b”在ASCII 字符中代表退格键,\b”在正则表达式中代表“匹配一个单词边界”
print(re.findall("\bblow","jason blowcat"))
#这里\b代表退格键,所以没有匹配到,返回空列表
print(re.findall("\\bblow","jason blowcat"))
#用\转义后这里就匹配到了,返回 ['blow']
print(re.findall(r"\bblow","jasonblow cat"))
#用原生字符串后就不需要转义了 ['blow']
在正则表达式里使用“\d”,没用原始字符串,也没出现什么问题。那是因为ASCII 里没有对应的特殊字符,所以正则表达式编译器能够知道你指的是一个十进制数字。但是我们写代码本着严谨简单的原理,最好是都写成原生字符串的格式。