正则表达式
1.正则表达式
正则表达式用来匹配一段字符串,如果字符串符合正则表达式的规则要求,就会被提取出来。
开源中国提供的正则表达式测试工具:https://tool.oschina.net/regex/#
2.match()
Python的re库提供了整个正则表达式的实现,一个常用的匹配方法是match()。
match()方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,就返回匹配成功的结果;如果不匹配,就返回 None。
代码:
import re content = 'Hello 123 4567 World_This is a Regex Demo' print(len(content)) result = re.match('^Hello\s\d\d\d\s\d{4}\s\w{10}', content) #\d后可以跟{4}代表匹配前面的规则4次 #第一个参数传入了正则表达式,第二个参数传入了要匹配的字符串 print(result) print(result.group()) print(result.span())
运行结果:输出
41 <re.Match object; span=(0, 25), match='Hello 123 4567 World_This'> Hello 123 4567 World_This (0, 25)
匹配目标
可以使用括号()将想提取的子字符串括起来,()实际上标记了一个子表达式的开始和结束位置,
被标记的每个子表达式会依次对应每一个分组,调用group()方法传入分组引索即可获取提取的结果。
代码:
import re content='Hello 1234567 World_This is a Regex Demo' result=re.match('^Hello\s(\d+)\sWorld',content) print(result) print(result.group()) print(result.group(1)) print(result.span())
运行结果:输出
<re.Match object; span=(0, 19), match='Hello 1234567 World'> Hello 1234567 World 1234567 (0, 19)
假如正则表达式后面还有其他(),可以依次用group(2)、group(3)来取。
通用匹配
. 点可以匹配任意字符, * 星代表匹配前面的字符无限次。
使用这些改写上面的正则表达式。
代码:
import re content='Hello 123 4567 World_This is a Regex Demo' result=re.match('^Hello.*Demo$',content) print(result) print(result.group()) print(result.span())
运行结果:输出
<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'> Hello 123 4567 World_This is a Regex Demo (0, 41)
中间部分全部被忽略了。
贪婪与非贪婪
贪婪匹配下.*会匹配尽可能多的的字符。
非贪婪匹配下.*?会匹配尽可能少的字符。
如果非贪婪匹配在字符串结尾,可能会匹配不到任何内容。
所以在匹配时,在字符串中间尽可能使用非贪婪匹配。
修饰符
正则表达式可以包含一些可选标志修饰符来控制匹配模式。
如果在字符串中加入换行符。
代码:
import re content='''Hello 123 4567 World_This is a Regex Demo ''' result=re.match('^He.*?(\d+).*?Demo$',content) print(result.group(1))
运行结果会报错。
加一个修饰符re.S就可以修复这个错误。
result=re.match('^He.*?(\d+).*?Demo$',content,re.S)
re.S的作用是使 . 可以匹配换行符在内的所有字符,除此之外还有许多修饰符。
转义匹配
如果目标字符串包含 . , 可以在前面加反斜线转义即可。
代码:
import re content='www.baidu.com' result=re.match('www\.baidu\.com',content) print(result)
运行结果:输出
<re.Match object; span=(0, 13), match='www.baidu.com'>
成功匹配所有字符串。
3.search()
match()是从开头匹配的,一旦开头不匹配,那么整个匹配就失败了,所以它更适合用来测试某个字符串是否符合某个正则表达式的规则。
而search()方法在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,如果搜索完了还没有找到,就返回None。
代码:
#coding:gbk import re html = '''<div id="songs-list"> <h2 class="title"> 经典老歌 </h2> <p class="introduction"> 经典老歌列表 </p> <ul id="list" class="list-group"> <li data-view="2"> 一路上有你 </li> <li data-view="7"> <a href="/2.mp3" singer="任贤齐"> 沧海一声笑 </a> </li> <li data-view="4" class="active"> <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="邓丽君"> 但愿人长久 </a> </li> </ul> </div>''' result=re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S) if result: print(result.group(1),result.group(2))
运行结果:输出
齐秦 往事随风
4.findall()
findall()方法搜索整个字符串,获取匹配正则表达式的所有内容。
代码:
#coding:gbk import re html = '''<div id="songs-list"> <h2 class="title"> 经典老歌 </h2> <p class="introduction"> 经典老歌列表 </p> <ul id="list" class="list-group"> <li data-view="2"> 一路上有你 </li> <li data-view="7"> <a href="/2.mp3" singer="任贤齐"> 沧海一声笑 </a> </li> <li data-view="4" class="active"> <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="邓丽君"> 但愿人长久 </a> </li> </ul> </div>''' results=re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',html,re.S) print(results) print(type(results)) for result in results: print(result) print(result[0],result[1],result[2])
运行结果:输出
[('/2.mp3', '任贤齐', ' 沧海一声笑 '), ('/3.mp3', '齐秦', ' 往事随风 '), ('/4.mp3', 'beyond', ' 光辉岁月 '), ('/5.mp3', '陈慧琳', ' 记事本 '), ('/6.mp3', '邓丽君', ' 但愿人长久 ')] <class 'list'> ('/2.mp3', '任贤齐', ' 沧海一声笑 ') /2.mp3 任贤齐 沧海一声笑 ('/3.mp3', '齐秦', ' 往事随风 ') /3.mp3 齐秦 往事随风 ('/4.mp3', 'beyond', ' 光辉岁月 ') /4.mp3 beyond 光辉岁月 ('/5.mp3', '陈慧琳', ' 记事本 ') /5.mp3 陈慧琳 记事本 ('/6.mp3', '邓丽君', ' 但愿人长久 ') /6.mp3 邓丽君 但愿人长久
返回的列表中的每个元素都是元组类型。
5.sub()
sub()方法可以利用正则表达式来修改文本。
代码:
import re content='4j559fbjfd9fsjb934jv' content=re.sub('\d+','',content) print(content)
运行结果:输出
jfbjfdfsjbjv
可以将其中的数字去除掉。
或者将文本中的a节点全部去掉。
代码:
#coding:gbk import re html = '''<div id="songs-list"> <h2 class="title"> 经典老歌 </h2> <p class="introduction"> 经典老歌列表 </p> <ul id="list" class="list-group"> <li data-view="2"> 一路上有你 </li> <li data-view="7"> <a href="/2.mp3" singer="任贤齐"> 沧海一声笑 </a> </li> <li data-view="4" class="active"> <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="邓丽君"> 但愿人长久 </a> </li> </ul> </div>''' html=re.sub('<a.*?>|</a>','',html) print(html) result=re.findall('<li.*?>(.*?)</li>',html,re.S) for result in results: print(result.strip())
运行结果:输出
<div id="songs-list"> <h2 class="title"> 经典老歌 </h2> <p class="introduction"> 经典老歌列表 </p> <ul id="list" class="list-group"> <li data-view="2"> 一路上有你 </li> <li data-view="7"> 沧海一声笑 </li> <li data-view="4" class="active"> 往事随风 </li> <li data-view="6"> 光辉岁月 </li> <li data-view="5"> 记事本 </li> <li data-view="5"> 但愿人长久 </li> </ul> </div> Traceback (most recent call last): File "retest_8.py", line 27, in <module> for result in results: NameError: name 'results' is not defined PS D:\spider> python retest_8.py <div id="songs-list"> <h2 class="title"> 经典老歌 </h2> <p class="introduction"> 经典老歌列表 </p> <ul id="list" class="list-group"> <li data-view="2"> 一路上有你 </li> <li data-view="7"> 沧海一声笑 </li> <li data-view="4" class="active"> 往事随风 </li> <li data-view="6"> 光辉岁月 </li> <li data-view="5"> 记事本 </li> <li data-view="5"> 但愿人长久 </li> </ul> </div> 一路上有你 沧海一声笑 往事随风 光辉岁月 记事本 但愿人长久
6.compile()
compile()方法可以将正则字符串编译成正则表达式对象,以便在后面的匹配中复用。
代码:
import re content1='2016-12-15 12:00' content2='2016-12-17 12:55' content3='2016-12-22 13:21' pattern=re.compile('\d{2}:\d{2}') #将正则表达式编译成为一个正则表达式对象,以便复用 result1=re.sub(pattern, '', content1) result2=re.sub(pattern, '', content2) result3=re.sub(pattern, '', content3) print(result1, result2, result3)
运行结果:输出
2016-12-15 2016-12-17 2016-12-22
compile()方法也可以传入修饰符,如re.S。
参考用书《python3网络爬虫开发实战》