day26

1.内容回顾

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':lst.pop()
   elif lst[-1].get(inp):
       lst.append(lst[-1][inp])


使用listdir求文件夹的大小
import os
lst = [r'D:\code']
size = 0
while lst:
   path = lst.pop()
   name_lst = os.listdir(path)
   for name in name_lst:
       full_path = os.path.join(path,name)
       if os.path.isdir(full_path):
           lst.append(full_path)
       elif os.path.isfile(full_path):
           size += os.path.getsize(full_path)
print(size)

三级目录  自己创建文件和文件夹 自己去打印每一次while循环过程中lst的变化,把这个题搞清楚

 

posted @ 2020-05-26 22:58  投降输一半!  阅读(197)  评论(0编辑  收藏  举报