day26
1.1 元字符
\d 所有的数字
\w 数字字母下划线
\s 空白(空格 换行符 制表符)
\D 非数字
\W 非数字字母下划线
\S 非空白
\t 制表符
\n 换行符
. 除换行符之外的任意字符
[] 匹配[]内所有的字符
[^] 不匹配[]内的所有字符
^ 以。。。开始
$ 以。。。结束
| 两种情况选一起,如果有规则重复,那么把长的放前面、
或只负责把两个表达式分开,如果是在整个表达式中只对一部分内容进行或,需要分组
() 限定|的作用域
限定一组正则的量词约束 (\d\w)?
1.2 量词
?
+
*
{n}
{n,}
{n,m}
1.3 贪婪匹配
默认 在规则和量词范围内尽量多匹配
回溯算法
1.4 惰性匹配(非贪婪匹配)
尽量少的匹配
.*?x 表示 匹配任意的内容直到遇到一个x就停止
默写的两个题
以a开头,由至少一个字母组成的字符串
^a[a-zA-Z]+
^a[a-zA-Z]*
以1开头,中间3-5个数字,如果中间位置超过5个数字,则整个字符串不匹配
^1\d{3,5}$
2.转义符
print('\\\\n')
print('\\n')
print(r'\\n')
print(r'\n')
正则表达式中的转义符在python的字符串中也刚好有转义的作用
但是正则表达式中的转义符和字符串中的转义符并没关系
且还容易有冲突
为了避免这种冲突
我们所有的正则都以在工具中的测试结果为结果
然后只需要在正则和待匹配的字符串外面都加r即可
3.re模块
import re
regex
ret = re.findall('\d+','alex83') #第一个参数为正则表达式 第二个参数为待匹配得字符串
print(ret)
findall 会匹配字符串中所有符合规则的项
并返回一个列表
如果未匹配到返回空列表
ret = re.search('\d+','alex83')
print(ret) # 如果能匹配上返回一个对象,如果不能匹配上返回None
if ret:
print(ret.group()) # 如果是对象,那么这个对象内部实现了group,所以可以取值
• \# 如果是None,那么这个对象不可能实现了group方法,所以报错
会从头到尾从带匹配匹配字符串中取出第一个符合条件的项
如果匹配到了,返回一个对象,用group取值
如果没匹配到,返回None,不能用group
re.match
ret = re.match('\d','alex83') == re.search('^\d','alex83')
print(ret)
会从头匹配字符串中取出从第一个字符开始是否符合规则
如果符合,就返回对象,用group取值
如果不符合,就返回None
match = search + ^正则
进阶方法
1.时间复杂度 效率 compile
在同一个正则表达式重复使用多次的时候使用能够减少时间的开销
2.空间复杂度 内存占用率 finditer
在查询的结果超过1个的情况下,能够有效的节省内存,降低空间复杂度,从而也降低了时间复杂度
3.用户体验
import re
ret = re.findall('\d','safhl02urhefy023908'*20000000)
print(ret)
ret = re.finditer('\d','safhl02urhefy023908'*20000000) # ret是迭代器
for i in ret: # 迭代出来的每一项都是一个对象
print(i.group()) # 通过group取值即可
compile
s = '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' \
'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>'
ret = re.compile(s) # 统一先编译此正则表达式,便于后期代码复用
print(ret)
r1 = ret.search('alex83') # 使用前方编译好得结果直接调用匹配方法
print(r1)
ret.findall('wusir74')
ret = re.compile('\d+')
r3 = ret.finditer('taibai40')
for i in r3:
print(i.group())
findall search
finditer compile
sub
split
import re
ret = re.split('\d(\d)','alex83wusir74taibai') #切割 # 默认自动保留分组中的内容
print(ret)
ret = re.sub('\d','D','alex83wusir74taibai',1) # 在第三个参数中,将第一个参数替换成第二个参数,第四个参数如果有,则确定替换掉几个匹配到的元素
print(ret)
ret = re.subn('\d','D','alex83wusir74taibai') # 同替换,返回值为元组,第一个参数为替换完得到的新内容,第二个参数为一共替换了几个
print(ret)
findall 参数顺序和数据类型,返回值类型
search
match
finditer
compile
sub subn
split
4.分组
s1 = '<h1>wahaha</h1>'
s2 = '<a>wahaha ya wahaha</a>'
s1 -> h1 wahaha
s2 -> a wahaha ya wahaha
import re
ret = re.search('<(\w+)>(.*?)</\w+>',s1)
print(ret)
print(ret.group(0)) # group参数默认为0 表示取整个正则匹配的结果 # <h1>wahaha</h1>
print(ret.group(1)) # 取第一个分组中的内容 # h1
print(ret.group(2)) # 取第二个分组中的内容 # wahaha
ret = re.search('<(?P<tag>\w+)>(?P<cont>.*?)</\w+>',s1)
print(ret)
print(ret.group('tag')) # 取tag分组中的内容
print(ret.group('cont')) # 取cont分组中的内容
分组命名
(?P<名字>正则表达式)
引用分组 (?P=组名) 这个组中的内容必须完全和之前已经存在的组匹配到的内容一模一样
s1 = '<h1>wahaha</h1>'
s2 = '<a>wahaha ya wahaha</a>'
ret = re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',s1)
print(ret.group('tag'))
s1 = '<h1>wahaha</h1>'
s2 = '<a>wahaha ya wahaha</a>'
ret = re.search(r'<(\w+)>.*?</\1>',s1) # 若分组未命名,调用时使用\1调用第一个分组,\2第二个
print(ret.group(1))
import re
ret = re.findall('\d(\d)','aa1alex83')
# findall遇到正则表达式中的分组,会优先显示分组中的内容
print(ret) # 3
ret = re.findall('\d+(?:\.\d+)?','1.234+2') # 在分组里标注 ?: 表示取消优先显示分组内容
print(ret)
分组
split
会保留分组中本来应该被切割掉的内容
分组命名
(?P<名字>正则) search group('组名')
引用分组
(?P=组命) 表示这个组中的内容必须和之前已经存在的一组匹配到的内容完全一致
分组和findall
默认findall 优先显示分组内的内容
取消分组优先显示 (?:正则)
例题
有的时候我们想匹配的内容包含在不相匹配的内容当中,这个时候只需要把不想匹配的先匹配出来,再通过手段去掉
import re
ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
ret.remove('')
print(ret)
5.正则表达式爬虫示例
import requests
import json
import re
def parser_page(par,content):
res = par.finditer(content)
for i in res:
yield {'id': i.group('id'),
'title': i.group('title'),
'score': i.group('score'),
'com_num': i.group('comment_num')}
def get_page(url):
ret = requests.get(url)
return ret.text
pattern = '<div class="item">.*?<em class="">(?P<id>\d+)</em>.*?<span class="title">(?P<title>.*?)</span>.*?' \
'<span class="rating_num".*?>(?P<score>.*?)</span>.*?<span>(?P<comment_num>.*?)人评价</span>'
par = re.compile(pattern,flags=re.S)
num = 0
with open('movie_info',mode = 'w',encoding='utf-8') as f:
for i in range(10):
content = get_page('https://movie.douban.com/top250?start=%s&filter=' % num)
g = parser_page(par,content)
for dic in g:
f.write('%s\n'%json.dumps(dic,ensure_ascii=False))
num += 25
# send 方法
def func():
print(123)
n = yield 'aaa'
print('-->',n)
yield 'bbb'
g = func()
print(g)
n = next(g) # 123
print(n) # aaa
print('-'*20)
# n2 = next(g) 等同于 n2 = g.send()
n2=g.send('uysdfhfoiusyg') #将send方法传入得值赋给上一次yield得返回值,但是原来的n不变
print(n2)
import requests
import json
import re
def parser_page(par,content):
res = par.finditer(content)
for i in res:
yield {'id': i.group('id'),
'title': i.group('title'),
'score': i.group('score'),
'com_num': i.group('comment_num')}
def get_page(url):
ret = requests.get(url)
return ret.text
def write_file(file_name):
with open(file_name,mode = 'w',encoding='utf-8') as f:
while True:
dic = yield
f.write('%s\n' % json.dumps(dic, ensure_ascii=False))
pattern = '<div class="item">.*?<em class="">(?P<id>\d+)</em>.*?<span class="title">(?P<title>.*?)</span>.*?' \
'<span class="rating_num".*?>(?P<score>.*?)</span>.*?<span>(?P<comment_num>.*?)人评价</span>'
par = re.compile(pattern,flags=re.S)
num = 0
f = write_file('move2')
next(f)
for i in range(10):
content = get_page('https://movie.douban.com/top250?start=%s&filter=' % num)
g = parser_page(par,content)
for dic in g:
f.send(dic)
num += 25
f.close()
# def func():
# print(123)
# n = yield 'aaa'
# print('-->',n)
# yield 'bbb'
#
# g = func()
# print(g)
# n = next(g)
# print(n)
# print('-'*20)
# next(g) # g.send('uysdfhfoiusyg')
6.总结
re模块
转义符
python中的方法
findall
search
match
finditer
complie
split
sub
subn
python中的方法 + 正则表达式的新内容
分组 split findall
分组命名
引用分组
爬虫的小例子
生成器的send
整理基础的概念
正则 ?都能做什么
小练习
7点 :
计算器的作业
listdir计算文件夹大小
7.栈
menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'老男孩': {},
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'山东': {},
}
三级菜单
递归
def menu_func(menu):
while True:
for key in menu:
print(key)
inp = input('>>>').strip()
if inp.upper() == 'Q': return 'q'
if inp.upper() == 'B': return 'b'
elif menu.get(inp):
flag = menu_func(menu[inp])
if flag == 'q': return 'q'
menu_func(menu)
print('ashkskfhjhflhs')
栈
menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'老男孩': {},
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'山东': {},
}
lst = [menu] # 就是列表里面一个字典元素····
while lst:
for key in lst[-1]:
print(key)
inp = input('>>>') # 北京
if inp.upper() == 'Q':break
elif inp.upper() == 'B':