re、正则
re模块和正则表达式的关系
- 有了re模块就可以在python语言中操作正则表达式了
什么是正则表达式?
- 一套规则,用来匹配字符串的规则
能做什么?
- 检查一个字符串的输入是否合法 -----web开发项目、表单验证
- 用户输入一个内容的时候,我们要提前检测,能够提高程序的效率并且减轻服务器的压力
- 从一个大文件中找到所以符合规则的内容 ----------日志分析、爬虫
- 能够高效的从一段文字中快速找到符合规则的内容
正则规则,元字符
- 所有规则中的字符就可以刚好匹配到字符串中的内容
- 在正则表达式中能够帮助我们表示匹配的内容的符号称为正则中的元字符如([],\d,\w等)
- 字符组:[] 描述的是一个位置上出现的所有可能性
- [abc] 一个中括号只表示一个字符位置([abc] [abc]这样才表示两个位置)
- [0-9] 可以匹配0-9之间的数字,因为[]是根据ascii进行的范围对比
- [a-z],[A-Z],[A-z]可以,[a-Z]不可以,'-'左右必须按照ascii中的顺序从小到大,不可以从大到小(a:97,Z:90)
- [0-9a-zA-Z]
- \d:可以匹配任意一位数字 (digit) \D:非数字
- \w:可以匹配任意一位数字、字母、下划线(word) \W:非数字字母下划线
- \s:匹配所有空白(空格、tab、回车) \S: 非空格
- 空格 :空格
- tab:\t
- enter:\n
- [\d\D] [\w\W] [\s\S]:表示匹配所有
- . :表示匹配除换行符enter 之外的所有
- [^]:表示匹配非字符组(
[^1]
表示匹配除1之外的所有内容) - ^:表示匹配一个字符串的开始
- $:表示匹配一个字符串的结尾
- a表达式|b表达式:匹配a,b表达式的内容,如果a匹配成功就不会和b匹配,所有两个规则有重叠部分,通常把长的放在前面
- ():约束| 描述的内容的范围问题
量词
-
{n}:表示匹配n次
-
{n,}:表示匹配至少n次
-
{n,m}:表示至少匹配n次,至多m次
-
?:表示匹配0次或一次
-
+:表示1次或多次
-
*:表示0次或多次
-
匹配小数:\d+\ .\d+
-
匹配整数或小数:\d+\ .?\d+
小练习
- 匹配11位的手机号,第一位必须是1,第二位必须是3-9
- ^1[3-9]\d{9}&
- 从一个大文件中寻找符合格式的手机号码
- 1[3-9]\d
- 匹配15或18为的身份证号码
- ^([1-9]\d{16}[0-9x]|[1-9]\d{14})$
贪婪匹配和惰性匹配
贪婪匹配:在量词范围允许的情况下,尽量多的匹配内容 ( \d{3,}9 匹配到字符串中最后一个9出现的位置)
惰性匹配:在量词范围允许的情况下,尽量少的匹配内容 ( \d{3,}?9 匹配到字符串中第三位元素后第一个9出现的出现的位置(匹配?后面元素出现的第一个位置停止(在没有至少的情况下,如果有则从至少后面开始匹配)))
转义符:\或把.()*?+元字符放在字符组里面
- 原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义
- 有一些特俗意义的内容,放在字符组中,会取消它的特俗意义
- -在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面或最后面
- [.()*?+]放在字符组中会取消它的特殊意义
findall、search
-
findall:按照完整的正则进行匹配,取所有符合条件的,只显示括号里显示的内容
ret1=re.findall('6(\d)\d','df697ghjkljj689jj') #55648fgh4544jk5445 print(ret1) #得['9','8'] 在满足条件的情况下返回元组的内容
-
取消优先显示(?:正则)
ret=re.findall('(?:<\w+>)(\w+)</\w+>','<h1>4888255fghjk65448</h1>') print(ret) #得['4888255fghjk65448']
-
search:按照完整的正则进行匹配,只取第一个符合条件的,显示匹配到的第一个内容用group获取、在第一个符合条件的元素中,但是我们可以通过给group传参数的方式获取具体分组中的内容
ret2=re.search('6(\d)(\d)','6789ooooo9999') print(ret2.group()) #得:678
- group()传参
- group(0)和group()的结果一致
- 使用group(n)的形式来指定第n个分组中匹配到的内容
ret2=re.search('6(\d)(\d)','6789ooooo9999') print(ret2.group(1)) #得 7 ret2=re.search('6(\d)(\d)','6789ooooo9999') print(ret2.group(2)) #得 8
-
小练习
- findall()是对需要的内容进行提取
ret=re.findall('<\w+>(\w+)</\w+>','<h1>4888255fghjk65448</h1>') print(ret) #得['4888255fghjk65448']
- group()传参
re模块中的方法
split切割 +()保留切割内容
s1=re.split('\d+','fdf55548gh444j')
print(s1)
# 得['fdf', 'gh', 'j']
s2=re.split('(\d+)','fdf55548gh444j')
print(s2)
# 得['fdf', '55548', 'gh', '444', 'j']
sub 替换,把所有数字替换成o
# sub 替换,把所有数字替换成o
s1=re.sub('\d','o','fdf55548gh444j')
print(s1)
# 得 fdfoooooghoooj
subn 返回一个元组(替换后的字符串,替换的次数)
# subn 返回一个元组(替换后的字符串,替换后的次数)
s1=re.subn('\d','o','fdf55548gh444j')
print(s1)
# 得 ('fdfoooooghoooj', 8)
match match和^差不多,判断开头
# match match和^差不多,判断开头
s4=re.match('\d+','55548fdfgh444j')
print(s4.group())
# 得55548,如果不是返回None
compile 节省时间
- 假如同一个正则表达式要被使用多次,使用compile多次解析一个正则表达式所需要的时间
ret=re.compile('\d+')
ret1=ret.search('55548fdfgh444j')
ret2=ret.findall('55548fdfgh444j')
print(ret1.group())
print(ret2)
# 55548
# ['55548', '444']
finditer 迭代器 -----节省空间
# finditer 迭代器 -----节省空间
ret=re.finditer('\d+','55548fdfgh444j')
for i in ret:
print(i.group())
得:
55548
444
compile和finditer可结合使用,节省空间和时间
# compile和finditer可结合使用,节省空间和时间
ret=re.compile('\d+')
ret1=ret.finditer('55548fdfgh444j')
for i in ret1:
print(i.group())
# 得
# 55548
# 444
分组命名
-
(?P<名称>) 取值:group(’名称‘)
ret=re.search('<(\w+)>(?P<name>\w+)</(\w+)>','<h1>ffghjklfgjhk</h1>') print(ret.group('name')) # 得:ffghjklfgjhk
-
分组命名的引用
- 有的时候我们要匹配的内容,是包含在不想要的内容之间的,这时候我们要将所有的内容匹配出来,然后在想办法从结果中去掉
- r'<(\w+)>\w+</\1>'
- <(?P
\w+)>\w+</(?P=name)>
ret=re.search(r'<(\w+)>\w+</\1><(\w+)>\w+</\2>','<h1>ffghjklfgjhk</h1><h1>ffghjklfgjhk</h1>') print(ret.group()) # 得:<h1>ffghjklfgjhk</h1><h1>ffghjklfgjhk</h1> ret=re.search(r'<(?P<name>\w+)>\w+</(?P=name)><(?P<name1>\w+)>\w+</(?P=name1)>','<h1>ffghjklfgjhk</h1><h2>ffghjklfgjhk</h2>') print(ret.group()) # <h1>ffghjklfgjhk</h1><h1>ffghjklfgjhk</h1>