re模块
正则
# re模块和正则表达式 re模块本质上和正则表达式没有一毛钱的关系
# 正则表达式不仅在python领域,在整个编程届都占有举足轻重的地位。
# 正则表达式本身也和python没有什么关系,就是匹配字符串内容的一种规则。
# 官方定义:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,
# 这个“规则字符串”用来表达对字符串的一种过滤逻辑。
字符组 元字符
# 字符组 : [字符组]
# 在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示
# [0-9] [a-z] [A-Z] [0-9a-fA-F]
# 元字符 都是代表匹配一个
# . 匹配除换行符以外的任意字符
# \w 匹配字母或数字或下划线
# \s 匹配任意的空白符
# \d 匹配数字
# \n 匹配一个换行符
# \t 匹配一个制表符
# ^ 匹配字符串的开始
# $ 匹配字符串的结尾
# \W匹配非字母或数字或下划线
# \D匹配非数字
# \S匹配非空白符
# a| b匹配字符a或字符b
# ()分组 匹配括号内的表达式,也表示一个组 列www\.(baidu|jd|taobao)\.com
# [...] 匹配字符组中的字符 列[\d\D]匹配所有 [\d\n] 一个[]代表一个字符
# [ ^ ...] 匹配除了字符组中字符的所有字符 列 [^1] 除了1的所有 一个[]代表一个字符
量词
# 量词
# * 重复零次或更多次
# + 重复一次或更多次 贪婪
# ? 重复零次或一次
# {n} 重复n次 列\d{2} 只可以匹配2个
# {n,} 重复n次或更多次 列\d{2,} 只可以匹配2个以上
# {n,m} 重复n到m次
# 特殊的符号
# . 匹配除了换行符之外的所有
# ^ 尖角号 在字符组中[^]代表非 在外面代表匹配一一个字符串的开始 列 ^a 以a开头
# $ 代表匹配一一个字符串的结尾 列 ^a 以a结尾
贪婪匹配与非贪婪
# 贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
# .* .*?
# 几个常用的非贪婪匹配Pattern
# *? 重复任意次,但尽可能少重复
# +? 重复1次或更多次,但尽可能少重复
# ?? 重复0次或1次,但尽可能少重复
# {n,m}? 重复n到m次,但尽可能少重复 只可以匹配n到m个
# {n,}? 重复n次以上,但尽可能少重复
# . 是任意字符
# * 是取 0 至 无限长度
# ? 是非贪婪模式。
# 何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
# .*?x
# 就是取前面任意长度的字符,直到一个x出现
转义符
# 转义符问题
# . 有特殊的意义,取消特殊的意义\.
# 取消一个元字符的特殊意义有两种方法
# 在这个元字符前面加\
# 对一部分字符生效,把这个元字符放在字符组里
# [.()+?*]
re模块
findall search
import re
# findall 利用re模块可以解决的问题在不规则字符串中利用正则匹配出想要得到结果 返回列表 取所有符合条件的,优先显示分组中的
#元祖形式 一个()代表元祖中一个内容
# search 显示匹配到的第一个内容 对象应该是 利用group()获得数字 只取第一个符合条件的,没有优先显示这件事儿
# 变量.group() 的结果 完全和 变量.group(0)的结果一致
# 变量.group(n) 的形式来指定获取第n个分组中匹配到的内容 假如我优先分组了2个我取3个就报错
# 为什么在 search 中不需要分组优先 而在findall中需要?
# 如果没有分组优先 我们想要取到想要的内容就要fro循环 和切片麻烦 (加上括号 是为了对真正需要的内容进行提取)
# 加上括号 是为了对真正需要的内容进行提取
# 如何取消分组优先
# 如果在写正则的时候由于不得已的原因 导致不要的内容也得写在分组里
# (?:) 取消这个分组的优先显示
# 加上括号 是为了对真正需要的内容进行提取
ret = re.findall('<\w+>(\w+)</\w+>','<h1>111</h1><h1>2222</h1>')
print(ret)#['111', '2222']
# search
ret = re.search('<(\w+)>(\w+)</\w+>','<h1>111</h1><h1>2222</h1>')
print(ret)#<re.Match object; span=(0, 12), match='<h1>111</h1>'> 变量
print(ret.group())#<h1>111</h1>
print(ret.group(1))#z1
print(ret.group(2))#111
print(ret.group(3))#会报错 为什么 优先分组了2个 我取3个当然报错
re其他方法
import re
# re方法
# findall()优先分组全部返回 serch()优先分组第一个 split() sub() subn() match() compile() finditer()
# split其实就是把匹配出来的字符串切了,带括号的保留,(括号必须在字符串里面)返回列表
# ret = re.split('\d+','alex222wusir')#将匹配出来的222切掉但加了括号就保留了 变成列表['alex', '123', 'wusir']
# ret = re.split('(\d\d\d)','alex123wusir')#将匹配出来的222切掉,但是保留分组优先['alex', '2', 'wusir']
# ret = re.split('\d(\d)\d','alex123wusir')#将匹配出来的222切掉,但是保留分组优先['alex', '2', 'wusir']
# sub 替换
# ret = re.sub('\d+','H','alex123wusir456',1)#将匹配出来的字符串进行替换,第3个参数是替换前几个
# ret = re.sub('\d+','H','alex123wusir456')#alexHwusirH
# subn
# ret = re.subn('\d+','H','alex123wusir456')#返回元祖 不仅替换还告诉你替换的次数('alexHwusirH', 2)
# match 想当与加了一个尖角好 和group()一样 一般用作用户输入
# ret = re.match('\d+','123eva456taibai')#<re.Match object; span=(0, 3), match='123'>
# ret = re.match('\d+','eva456taibai')#None 结果为什么是none 他相当与人为加了一个尖角号 之会匹配开头第一个
# ret = re.search('^\d+','123eva456taibai')#与上面效果相同
# print(ret.group())
# 为什么^group() 和match()效果一样 但我们还有用他?
# 虽然效果相同都是找匹配出来的第一个但是match是规定这个字符号必须是什么样的
# 而group是用来寻找这个字符串中是不是含有满足条件的子内容 态度不同
# 用match我们可以用作用户输入时判断他输入的内容是不是和我的正则匹配
# match('手机号正则$','123eva456taibai')
# compile -- 节省代码时间的工具 可以与其他方法相结合 提高了效率
# 假如同一个正则表达式要被使用多次(爬虫时)
# 节省了多次解析同一个正则表达式的时间
# ret = re.compile('\d+')#预编译一遍 以后用的好拿来就用 不在需要重复理解这个正则了
# res1 = ret.search('alex37176') 与之前的效果一样
#a = re.sub(ret,'H','alex123wusir456',1)#与之前效果一样 但提升了效率
# finditer -- 节省空间 返回一个迭代器
# finditer -- 节省空间
ret = re.finditer('\d+','agks1ak018093')#返回迭代器 里面是变量 利用for循环取值
# ret = re.findall('\d+','agks1ak018093')#返回列表 取所有符合条件的,优先显示分组中的
for i in ret:#i是一个变量 老朋友了不懂重学。。。
print(i.group())#可以用
# 如何节省空间右提高了效率(其实所有的fro循环都消耗资源)
# 先compile(如果没有重复使用同一个正则,也不能节省时间)
# 再finditer
# 杂谈
# 功能 性能
# # 时间 :
# # 你要完成一个代码所需要执行的代码行数
# # 你在执行代码的过程中,底层程序是如何工作的
# # 空间
# # 是占用了宝贵的内存条资源
# # 影响程序的执行效率
# # 用户体验
re分组命名
# 问什么要有分组
# 爬虫时正则内容过长 像数据库子查询的起别名
import re
ret = re.search('\d(\d)\d(\w+?)(\d)(\w)\d(\d)\d(?P<name1>\w+?)(\d)(\w)\d(\d)\d(?P<name2>\w+?)(\d)(\w)',
'123abc45678agsf_123abc45678agsf123abc45678agsf')
# 利用group想要取某一个分组中数据 原本要数 麻烦还容易出错 所以出现了分组命名 格式--- (?P<名字>正则表达式)
# ret.group('名字')
print(ret.group('name1'))
print(ret.group('name2'))
# 分组命名的引用
# 分组命名(?P<组名1>正则)与(?P=组名1) 正则效果一样 后面的引用了前面的
# 有的时候我们要匹配的内容是包含在不想要的内容之中的,
# 只能先把不想要的内容匹配出来,然后再想办法从结果中去掉
# 应用场景
# import re
# exp= '<abc>akd7008&(&*)hgdwuih</abb>008&(&*)hgdwuih</abd>'
# ret= re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',exp)#加了问号就是非贪婪匹配
# print(ret)
import re
# exp= '<abc>akd7008&(&*)hgdwuih</abc>008&(&*)hgdwuih</abd>'
# ret= re.search(r'<(\w+)>.*?</\1>',exp)#\1表示你匹配的正则第一个内容 加r去转义 不好用 用分组命名 扩展
# 结论 在正则前面加r
collections模块
# 在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
# 1.namedtuple: 生成可以使用名字来访问元素内容的tuple
# 2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
# 3.Counter: 计数器,主要用来计数
# 4.OrderedDict: 有序字典
# 5.defaultdict: 带有默认值的字典
非学,无以致疑;非问,无以广识
非学,无以致疑;非问,无以广识