一、正则表达式
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
- 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配"):
- 可以通过正则表达式,从字符串中获取我们想要的特定部分。
很详细的教程:
https://www.oschina.net/question/12_9507
二、读书笔记
1:常用匹配方法——match()
作用
从字符串的起始位置匹配正则表达式(一旦开头不匹配,整个匹配都失败)
匹配则返回匹配成功的结果,即匹配到的字符串内容,否则返回None
(1)实例:
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)
print(result)
print(result.group())
print(result.span())
说明
- 首先打印出content长度:41
- 打印出匹配结果:sre_match对象,说明匹配成功。
- 该对象对应两个方法:
group()
输出匹配到的内容。span()
输出匹配的范围,即匹配到的结果字符串在原字符串中的位置范围。
运行结果:
41
<_sre.SRE_Match object; span=(0, 25), match='Hello 123 4567 World_This'>
Hello 123 4567 World_This
(0, 25)
(2)匹配目标实例
如果想从字符串中提取内容,则可以使用()
标记子表达式的开始和结束位置。示例:
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())
说明:
- 此处我们是将字符串中的1234567提取出来,所以将数字部分的正则表达式用()括起来。然后调用
group(1)
获取匹配结果。 group()
会输出完整的匹配结果。而group(1)
会输出第一个被()括号包围的匹配结果。加入正则表达式后面还有被()括起来的内容,可依次使用group(2)
group(3)
等来获取。
运行结果:
<_sre.SRE_Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
1234567
(0, 19)
(3)通用匹配实例
万能匹配.*
.
:匹配任意字符(除换行符)
*
:匹配前面字符任意次
改写上面例子:
import re
content = 'Hello 1234567 World_This is a Regex Demo'
print(len(content))
result = re. match ('^Hello.*Demo$', content)
print(result)
print(result.group())
print(result.span())
运行结果:
40
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
Hello 1234567 World_This is a Regex Demo
(0, 40)
(4)贪婪与非贪婪
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re. match ('^He.*(\d+).*Demo$', content)
print(result)
print(result.group(1))
运行结果:
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7
说明:
- 我们只得到了数字‘7’,但实际上我们想要得到的是中间的7个数字,原因:
.*
为贪婪匹配,会尽可能地多匹配字符。而括号中的(\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))
运行结果:
<_sre.SRE_Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
说明:
.*?
为非贪婪匹配,即尽可能少的匹配字符。则可以得到我们想要的结果- 在字符串中间匹配时多用非贪婪匹配。
修饰符
修饰符 | 描述 |
---|---|
re.I | 使匹配大小写不敏感 |
re.L | 本地化识别匹配 |
re.M | 多行匹配,影响^,$ |
re.S | 使.匹配换行符在内的所有字符 |
re.U | 根据unicode字符集解析字符,影响:\w\W\b\B |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |
网页中常用re.S&re.I
(5)转义匹配
如果目标字符串里面就包含特殊字符,前面加反斜杠\
即可
例如:
import re
content = '(百度)www.baidu.com'
result = re. match ('\(百度\)www\.baidu\.com', content)
print(result)
运行结果:
<_sre.SRE_Match object; span=(0, 17), match='(百度)www.baidu.com'>
2:常用匹配方法——search()
match()
必须要考虑开头内容,更适合检测字符串是否符合某个正则表达式的规则,做匹配时却多有不便。为了匹配方便,我们更常使用search()
方法。
作用
它在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果。
也就是说,正则表达式可以是字符串的一部分,在匹配时,search()
方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没有找到,就返回 None。
实例
网页源码:
<div class="explore-feed feed-item" data-offset="1">
<h2><a class="question_link" href="/question/28242987/answer/590122228" target="_blank" data-id="3479775" data-za-element-name="Title">
为什么路飞的船停在码头敌人都不会破坏船呢?
</a></h2>
代码:
import re
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36'
}
r=requests.get('http://www.zhihu.com/explore', headers=headers)
pattern=re.compile('explore-feed.*?question_link.*?>(.*?)</a>', re.S)
titles=re.search(pattern,r.text)
if titles:
print(titles.group(1))
运行结果:
为什么路飞的船停在码头敌人都不会破坏船呢?
3:findall()
search()
可以返回匹配正则表达式的第 个内容,但是如果想要获取匹配正则表达式的所有内容,就要借助 findall()
方法。
作用:
搜索整个字符串,然后返回匹配正则表达式的所有内容
实例:
import re
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3423.2 Safari/537.36'
}
r=requests.get('http://www.zhihu.com/explore', headers=headers)
pattern=re.compile('explore-feed.*?question_link.*?>(.*?)</a>', re.S)
titles=re.findall(pattern,r.text)
print(titles)
运行结果:
['\n为什么路飞的船停在码头敌人都不会破坏船呢?\n', '\n你遇到过最有教养的人是什么样的?\n', '\n如何高效地学习pytorch?\n', '\n高考历史选择题应该怎么做?\n', '\n如何评价朱一龙2019春晚的表现?\n', '\n接触人性阴暗面较多的是哪些职业?\n', '\n『明星大侦探』里何炅和撒贝宁,谁的逻辑更强?\n', '\n淘宝上有哪些「价格不高,格调很高」的东西?\n', '\n火影中,那些年被岸本吃掉的设定都有哪些?\n', '\n如何评价林俊杰?\n']
4:sub()
作用:
修改文本
实例:
代码:
import re
content = '54aK54yr5oiR54ix5L2g'
content = re.sub('\d+','',content)
print(content)
运行结果:
aKyroiRixLg
说明:
- 第一个参数为:匹配的字符,此处为所有的数字
- 第二个参数为:替换的字符串,此处为空
- 第三个参数为:原字符串
5:compile()
作用:
将正则字符串编译成正则表达式对象,以便在后面的匹配中复用。相当于给正则表达式做一层封装。
实例:
代码:
import re
content1 = '2018-02-02 12:00'
content2 = '2018-02-03 12:30'
content3 = '2018-02-03 12:20'
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)
结果:
2018-02-02 2018-02-03 2018-02-03
说明:
- 借助
sub()
去掉时间 - 没必要重复写3个同样的正则表达式,借助
compile()
方法即可将正则表达式编译成一个正则表达式对象,复用。 compile()
亦可传入修饰符。