http://tool.oschina.net/regex 在线正则表达式测试
常用方法
^
开头$
结尾\s
空格\d
数字\d{5}
5个数字\w
小写w 匹配字母+数字+下划线\W
大写 W 匹配非字母、非数字、非下划线.
匹配任意字符,除了换行符(但是在指定匹配模式 re.S
的时候就可以)*
匹配0-多个字符+
匹配一个或多个字符\s*?
匹配一个可能有,可能没有的空白字符\n
匹配一个换行符。等价于 \x0a 和 \cJ。
Jupyter Notebook
- pip install jupyter
- jupyter notebook 在命令行运行
re.match
尝试是字符串起始位置开始匹配的一个模式,如果匹配不成功,返回 Nonere.match(pattern,string,flags=0)
最常规的匹配
结果如下: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}.*Demo$',content)
# 【第一个参数是正则表达式的规则】,【第二个参数是被匹配的内容】
print(result)
#打印匹配结果信息
print(result.group())
# group 表示只打印匹配出来的结果
print(result.span())
# 输出匹配结果的范围
泛匹配
结果和上面的是一样的。import re
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello.*Demo$',content)
# 泛匹配,匹配 Hello Demo 中间的所有内容。
print(result)
print(result.group())
print(result.span())
匹配目标
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^Hello\s(\d+)\sWorld.*Demo$',content)
# 我们需要匹配的是1234567
# \d+ 表示匹配1个或多个数字
# () 内为需要匹配的内容
print(result)
print(result.group(1))
# group(1)表示第一个group,如果匹配规则有两个group,那第二个就是 group(2)
print(result.span())
我们需要匹配的是1234567 \d+ 表示匹配1个或多个数字 () 内为需要匹配的内容 group(1)表示第一个group,如果匹配规则有两个group,那第二个就是 group(2)
贪婪模式
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*(\d+).*Demo$',content)
# .* 贪婪识别
print(result)
print(result.group(1))
print(result.span())
结果如下,它只匹配到到了一个7, 因为(\d+)
前面的 .*
会匹配尽可能多的字符,而(\d+)
是需要匹配至少一个,由于前面是贪婪的,所以(\d+)
就只能得到一个数字了。
非贪婪模式
在
.*
后面加一个”问号”,变成.*?
就是匹配 尽量少 的字符。
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\d+).*Demo$',content)
# .*? 非贪婪识别
print(result)
print(result.group(1))
print(result.span())
这个时候结果就是1234567了 这个时候就让 (\d+)
尽量多的识别了字符
匹配模式(换行匹配)
import re
content = '''Hello 1234567 World_This
is a Regex Demo'''
# ''' 内容''' 是换行符的意思。如过按照上面的写法是无法匹配出结果的
result = re.match('^He.*?(\d+).*Demo$',content,re.S)
# 后面的re.S (大写 S)就可以让.匹配换行符了。
print(result)
print(result.group(1))
print(result.span())
转义
import re
content = 'price is $5.00'
result = re.match('price is \$5\.00',content)
print(result)
在这里 $
和.
需要在前面加一个 \
来把他们转义成字符串。 这样匹配出来的就没有问题。
总结:
尽量使用泛匹配、使用括号的到匹配目标,尽量使用费贪婪模式,有换行符就用re.S
re.search
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.match('Hello.*?(\d+).*?Demo',content)
print(result)
我们从中间开始匹配,结果如下
但是如果把 match 改成 search
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
result = re.search('Hello.*?(\d+).*?Demo',content)
# 把 match 改成 search
print(result)
这样就匹配成功了。
为了方便,能用search 就不用 match
匹配演练
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))
结果如下,这里匹配的结果是 带 class= active 的标签,如果去掉 active 那就会匹配第一个
任贤齐 沧海一声笑
re.findall
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])
匹配出歌词
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.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>',html,re.S)
# 第一个()和最后一个括号是匹配<a></a>, 因为一路上有你没有a标签,所有后面加个 ? 表示可能为0-多个。
# \s*? 表示0-多个空格
#print(results)
for result in results:
print(result[1])
re.sub
替换字符串中每一个匹配的子串后返回替换后的字符串。
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('\d','q',content)
#如果只写 \d 就会 1-7每个数字替换一次。qqqqqqq 效果如图1
# 如果写成\d+ 就会把1234567 替换成 q 效果如图2
# 第一个参数传入正则表达式,第二个参数传入要替换的内容,第三个参数传入元内容。
print(content)
包括内容再替换
import re
content = 'Extra stings Hello 1234567 World_This is a Regex Demo Extra stings'
content = re.sub('(\d+)',r'\1 q',content)
# 需要把替换内容放在一个小括号内,需要替换的内容要 r'\1' r是声明一下,然后\1表示前面的括号内容,再添加其他内容 包括空格就会一起替换 之前的 1234567
print(content)
替换再findall
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)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
#print(results)
for result in results:
print(result.strip())
#.strip()去掉换行符
re.compile
将一个正则表达式串编译成正则对象,以便于复用该匹配模式
import re
content = '''Hello 1234567 World_This
is a Regex Demo'''
pattern = re.compile('Hello.*Demo',re.S)
result = re.match(pattern,content)
# 先写一个正则表达式规则并且赋予 pattern ,
#下次就不用写正则表达式规则了,直接在规则那输入 pattern 就调用了这个正则表达式规则。
#result = re.match('Hello.*Demo',content,re.S)
#上面个语句表达出来的意思等同这次
print(result)
实战练习
import re
import requests
content = requests.get('https://book.douban.com/').text
pattern = re.compile('<li.*?cover.*?href="(.*?)".*?title="(.*?)".*?more-meta.*?author">(.*?)</span>.*?year">(.*?)</span>.*?</li>', re.S)
results = re.findall(pattern,content)
#print(results)
for result in results:
url,name,author,date = result
# 每个值是一个括号
author = re.sub('\s','',author)
date = re.sub('\s','',date)
# author 和date 带换行符,取消掉
print(url,name,author,date)
#print(url,name,author.strip(),date.strip()) #等同于上面两行的效果
结果如下