python--re模块, 正则表达式
正则表达式是对字符串操作的一种逻辑公式.我们一般使用正则表达式对字符串进行匹配和过滤.使用正则的优缺点:
有点:灵活,功能性强,逻辑性强
缺点: 上手难.一旦上手,会爱上这个东西
工具: 各大文本编辑器一般都由正则匹配功能. 我们可以去http://tool.chinaz.com/regex/ 在线使用工具进行测试
1. 正则表达式,匹配字符串
元字符
字符组很简单用[]括起来,在[]中出现的内容会被匹配,例如:[abc] 匹配a或b或c
如果字符组中的内容过多还可以使用-,
[a-zA-Z0-9] 匹配的是字母a-z或A-z或0-9中的任意一个
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的边界
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
量词
一次性匹配多个字符就要用到量词
* 重复0次或更多次
+ 重复1次或更多次
? 重复0次或1次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
惰性匹配和贪婪匹配
在量词中的 * , +, {} 都属于贪婪匹配,就是尽可能多的匹配到结果
.*? 尽可能少的匹配,表示惰性匹配
str: <div>胡辣汤</div>
reg: <.*>
结果: <div>胡辣汤</div>
str: <div>胡辣汤</div>
reg: <.*?>
结果:
<div>
</div>
str: <div>胡辣汤</div>
reg: <(div|/div*)?>
结果:
<div>
</div>
惰性匹配和贪婪匹配
贪婪
.* 尽可能多的匹配
.+
惰性:
.*?哈哈 尽可能少的匹配
分组:
使用括号()进行分组
转义:
在正则表达式中,有很多特殊意义的元字符,如果要在正则中匹配正常的\n而不是"换行符"就需要对"\"进行转义,太麻烦了,
所以我们就用到了r'\n'这个概念,为了打出 str ->' \n' ,此时的正则是r'\\n'就可以了
2. re 模块
在python中使用正则. re
(?P<name>正则) 用的时候直接 group("name")就可以了
1. search() 搜索. 搜索到第一个结果返回
search和match的区别: search查找. 找到了结果就返回. match. 从头开始匹配.
r = re.search("\d+","电话号码123456789")
print(r) # <_sre.SRE_Match object; span=(4, 13), match='123456789'>
print(r.group()) # 123456789
2. match() 匹配. 收到一个结果返回. 只能从字符串开头开始匹配
r = re.match("\d+","电话号码123456789")
print(r)
print(r.group())
结果
<_sre.SRE_Match object; span=(0, 3), match='123'>
123
所以显示出match是从字符串开始进行匹配
r = re.match("\d+","12312电话号码123456789")
print(r)
print(r.group())
结果
<_sre.SRE_Match object; span=(0, 5), match='12312'>
12312
3. findall() 查找所有匹配结果
r = re.findall("\d+","电话号码123456789")
print(r) # ['123456789']
4. finditer() 返回迭代器.
result = re.finditer(r"姓名:(?P<name>.*?), 爱好:(?P<hobby>.*?),", "姓名:小名, 爱好:女,")
for el in result:
print(el.group("name"), el.group("hobby"))
结果
<callable_iterator object at 0x000002044EBDF2E8>
<callable_iterator object at 0x000002044EBDF2E8>
小名 女
5. compile() 编译
reg = re.compile(r'\d+') # 加载了一段正则
lst = reg.findall("呵呵, 笨蛋才不去134呢.他要去1123了")
print(lst)
结果
['134', '1123']
6. group("name") 获取数据
result = re.finditer(r"姓名:(?P<name>.*?), 爱好:(?P<hobby>.*?),", "姓名:小名, 爱好:女,")
for el in result:
print(el.group("name"), el.group("hobby"))
结果
<callable_iterator object at 0x000002044EBDF2E8>
<callable_iterator object at 0x000002044EBDF2E8>
小名 女
7. re.S 去掉 . 的换行
在网页源码中有许多空白, re.S就是为了去掉这些空白
# 爬取电影天堂
from urllib.request import urlopen
content = urlopen("https://www.dytt8.net/html/gndy/dyzz/20181219/57954.html").read().decode("gbk")
# print(content)
reg = r'<div id="Zoom">.*?片 名(?P<name>.*?)<br />◎年 代(?P<years>.*?)<br />.*?◎上映日期(?P<date>.*?)<br />'+ \
'.*?◎主 演(?P<main>.*?)◎简 介.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">'
it = re.finditer(reg, content, re.S) # re.S 去掉.里面的\n
for el in it:
print(el.group("name"))
print(el.group("years"))
print(el.group("date"))
print(el.group("main").replace("<br /> ", ", "))
print(el.group("download"))
8. (?:) 把表达式从python中的正则分组变为正则表达式中的分组
lst = re.findall(r"a(?:\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组
print(lst)
lst = re.findall(r"a(\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组
print(lst)
结果
['a123456c']
['123456']
3. 其他操作
1.sub,替换目标字符串
ret = re.sub(r'\d+','__???__',"mike1446inn9988oeoeujt") # 把字符串中的数字替换成__???__ print(ret)
结果
# mike__???__inn__???__oeoeujt
2.subn,替换目标字符串并返回为元组,并对替换的次数计数
ret = re.subn(r'\d+','__???__',"mike1446inn9988oeoeujt")
print(ret)
结果
('mike__???__inn__???__oeoeujt', 2)
3.正则中的split()
ret = re.split('[ab]','qqqqeafiefubdkksd')
print(ret)
结果
['qqqqe', 'fiefu', 'dkksd']
注意事项:在匹配部分加上()之后所切出的结果是不同的
爬虫重点:
obj = re.compile(r'(?P<id>\d+)(?P<name>e+)') # 从正则表达式匹配的内容每个组起名字 ret = obj.search('abc123eeee') # 搜索 print(ret.group()) # 结果: 123eeee print(ret.group("id")) # 结果: 123 # 获取id组的内容 print(ret.group("name")) # 结果: eeee # 获取name组的内容
在匹配部分没有加()的话,不保留匹配部分
ret = re.split("\d+","eklfj3fe4efji") print(ret) # ['eklfj', 'fe', 'efji']
在匹配部分加了()的话,保留匹配部分
ret1 = re.split("(\d+)","eklfj3fe4efji") print(ret1) # ['eklfj', '3', 'fe', '4', 'efji']
lst = re.findall(r"a(?:\d+)c", "a123456c") # 把括号python中的分组变成了原来正则表达式中的分组