四、正则、
re模块:
作用:针对的对象:字符串,
课前引入:
例子一、
s='dsdsadsadadsalexdsds'
s.find('alex')
如何找到字符串内部的alex;?过去学习可使用方法:find、split、replace.但是字符串内置的方法很局限,只能实现完全匹配。
如果要找到:与a**开头的需求呢?就无法实现。要实现模糊匹配就得用到模糊匹配。
例子二、模糊匹配
#在文本里面存着一堆身份证 4504231989347382822 1104231989347382822 1104231992347382822 1104231995347382822 ..... #需求:找到北京市1990以后出身的人
^110......1990+*
找到一堆字符串里面的数字:
正则本质上是一种小型的,高度专业化的编程语言。(python)中内嵌在python中,并通过re模块来实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符匹配:(普通字符、元字符)
普通字符:大多数字符和字母都会和自身匹配
import re print(re.findall('alex','dsfjdsfldsjfdalexdsds')) >>> ['alex']
元字符:. ^ $ * + ?{} [] | () \
字符讲解:
1⃣️通配符 '.’
import re print(re.findall('a..x','dsfjdsfldsjfdalexdsds')) >>> ['alex']
2⃣️、尖角号:^ 以什么开头。在字符串的开头进行匹配。如果符合要求匹配成功。
import re print(re.findall('^d..j','dsfjdsfldsjfdalexdsds')) >>> ['dsfj']
3⃣️、$ 符号 以什么结尾,
import re print(re.findall('d..s$','dsfjdsfldsjfdalexdsds')) >>>> ['dsds']
重复符号:
4⃣️、* (0,∞) D*按照紧挨着的字符进行无穷次→贪婪匹配,
import re print(re.findall('d*','dsfjdsflddddddddddsjfdalexdsds')) >>> ['d', '', '', '', 'd', '', '', '', 'dddddddddd', '', '', '', 'd', '', '', '', '', 'd', '', 'd', '', '']
import re print(re.findall('^d*','dsfjdsflddddddddddsjfdalexdsds')) >> ['d']
????️、+ 匹配[1,∞)最少匹配一个字符尾部加一个?号就变成惰性匹配
import re print(re.findall('alex*','dsfjdsfalesjfdsds')) import re print(re.findall('alex+','dsfjdsflalesjfdsds')) >>> ['ale'] []
6⃣️、?[0,1]
import re print(re.findall('alex?','dsfjdsflalexxxsjfdsds')) >>> ['alex']
7⃣️、{} 范围自己定{0,}=*:0到无穷次、{1,}=+:【1,+00】、{0,1}=?、{6}重复6次
import re print(re.findall('alex{6}','dsfjdsflalexxxsjfdsds')) >>> []
7⃣️.1:? [0,1] 就变成 惰性匹配,按照最小的来查找匹配。
import re print(re.findall('alex+?','dsfjdsflalexxxsjfdsds')) import re print(re.findall('alex*?','dsfjdsflalexxxsjfdsds')) >>>> ['alex'] ['ale']
8⃣️、[]:字符集..任何符号放置在里面都是普通的符号,匹配里面的其中一个字符。里面的字符都是或的关系,之匹配其中的一个字符。
ret=re.findall('a[bc]d','acd') print(ret)#['acd']
ret=re.findall('[a-z]','acd') print(ret)#['a', 'c', 'd']
ret=re.findall('[.*+]','a.cd+') print(ret)#['.', '+']
除了一些特定功能:-、^、\
【a-z】范围,a到z
import re print(re.findall('x[a-z]*','xypsssdsdsdsdssxzp')) >>> ['xypsssdsdsdsdssxzp']
【^a-z】意义:非 匹配非a到z的字母
import re print(re.findall('www.[oldboy baidu]','www.baid')) import re print(re.findall('x[yz]','xyssssxz')) import re print(re.findall('x[yz]p','xypssssxzp')) >>> ['www.b'] ['xy', 'xz'] ['xyp', 'xzp']
【\】 转义字符、让元字符变成普通字符,让普通字符变成有代表性的字符
反斜杠后边跟元字符去除特殊功能,比如\.
反斜杠后边跟普通字符实现特殊功能,比如\d
\d 匹配任何十进制数;它相当于类 [0-9]。 查找数字:\d+ 查找字符串里面所有数字。
import re print(re.findall('\d+','asasa22jfdfddsd22jj23jk5jh55'))
>>>
['22', '22', '23', '5', '55']
\D 匹配任何非数字字符;它相当于类 [^0-9]。
import re print(re.findall('\D+','asasa22jfdfddsd22jj23jk5jh55')) >>> ['asasa', 'jfdfddsd', 'jj', 'jk', 'jh']
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
import re print(re.findall('I\\b','I am LIST')) #如何匹配出第一个。\\→、\ print(re.findall(r'I\b','I am LIST')) #r代表pytho解释器完全把\b传入正则中 >>> ['I'] ['I']
牛刀小试:a="12+(34*6+2-5*(2-1))"
思路:从最里层括号开始计算,:以括号开始中间没有括号。
import re a="12+(34*6+2-5*(2-1))" b=re.findall('\([^()]+\)',a) 元字符中有的符号,需要加上:\ 就变成普通括号 print(b) >>> ['(2-1)']
9⃣️、() 分组
import re print(re.findall('(abc)+','abcabcabcabcabc')) >>> ['abc']
ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com') print(ret.group())#23/com print(ret.group('id'))#23 #有名匹配
????、\ 转义字符
先看下面几个匹配例子:
import re ret=re.findall('c\l','abc\le') print(ret)#[]
ret=re.findall('c\\l','abc\le') print(ret)#[]
ret=re.findall('c\\\\l','abc\le') print(ret)#['c\\l']
ret=re.findall(r'c\\l','abc\le') print(ret)#['c\\l']
re.findall(r'I\b',"I am ooo") 加上r之后,python就不会转义特殊字符。or:\\b→转义为:\b
#-----------------------------eg2:
#之所以选择\b是因为\b在ASCII表中是有意义的
m
=
re.findall(
'\bblow'
,
'blow'
)
print
(m)
m
=
re.findall(r
'\bblow'
,
'blow'
)
print
(m)
解释:
在re模块里面: \也是有特殊意义,所以对于普通的\ 也需要经过转义:\\=\ 所以传到re里面需要是:a\\k才可以匹配到c\k
在python解释器中\也有特殊意义,所以要传入两个\\,就需要使用:\\\\→传入re变成:\\
11、
管道符:|
import re print(re.findall('ja|s','asasdds2j23jajs5jh55')) #|左右两部分为整体 >>>> ['s', 's', 's', 'ja', 's']
五、re模块下的常用方法
5.1、 re.search方法:
re.search('a','alvin yuan').group() #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
import re print(re.search('(?P<name>\w+)','alexalex')) #有名匹配 print(re.search('\d+','sndsakd332kkhjhl3h232jk')) >>>> <_sre.SRE_Match object; span=(0, 8), match='alexalex'> <_sre.SRE_Match object; span=(7, 10), match='332'>
#要想打印出来,加个:.group
print(re.search('\d+','sndsakd332kkhjhl3h232jk').group())
332
import re print(re.search('(?P<name>[a-z]+)\d+','alex36+wupeiqi34yuanhao33')) print(re.search('(?P<name>[a-z]+)\d+','alex36+wupeiqi34yuanhao33').group()) print(re.search('(?P<name>[a-z]+)','alex36+wupeiqi34yuanhao33').group('name')) #有名匹配
print(re.search('(?P<name>[a-z]+)(?P<age>\d+)','alex36wupeiqi34yuanhao33').group('age')) print(re.search('(?P<name>[a-z]+)(?P<age>\d+)','alex36wupeiqi34yuanhao33').group('name','age')) >>>
<_sre.SRE_Match object; span=(0, 6), match='alex36'> alex36 alex 36 ('alex', '36')
应用:对于优先级差不多的情况下:优先处理第一个符合要求的字符。
比如计算器应用:()+() 、 3+2-2
5.2、match。只能匹配开始的第一个。相当于用search匹配加了尖角号的字符
#3 re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配.x
import re print(re.match('a','abc').group()) >>> a
5.3、re.split(),切割
简单例子:
import re print(re.split('a','hello abc dea')) >>> ['hello ', 'bc de', '']
split和字符集
ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 划分的时候,对于两边没有内容的情况就会出现空格 print(ret) >>> ['', '', 'cd']
import re print(re.split('[ ae]','hello abc dea')) #先按照' '划分,等到结果,再按照a划分,得到结果,在按照a划分: ['h', 'llo', '', 'bc', 'd', '', '']
5.4、re.findall
re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里
补充注意点:当在匹配规则里面做了分组之后,findall会优先把匹配成功分组的内容显示出来。分组内部优先级会高些。
import re print(re.findall('www\.(baidu|163)\.com','www.baidu.com')) >>> ['baidu']
如果要降低分组内的优先级的话:加上(?:):去优先级分组的目的在于提取重点内容,对于海量数据的解决方案是有好处的!
import re print(re.findall('www\.(?:baidu|163)\.com','www.baidu.com163')) >>> ['www.baidu.com']
5.5、 替换:sub(pattern, repl, string, count=0, flags=0):count匹配前面的几次
import re print(re.sub('\d','A','hello12121ggii')) >>> helloAAAAAggii
5.6、 匹配替换:subn
#输出匹配结果和匹配次数,放置在一个元祖里面 ret=re.subn('\d','abc','alvin5yuan6') print(ret)
>>>>
#('alvinabcyuanabc', 2)
5.7、事先定好规则如:obj.然后接下来直接调用就可以
obj=re.compile('\d{3}') ret=obj.search('abc123eeee') print(ret.group()) #123
5.8、finditer。返回的结果是一个可迭代对象,可以用.next来输出下一个。用.group 来完整输出数字
实际用处:
对于匹配的数据结果是海量的时候!如果是使用findall会一下子放置在一个列表中,爆内存
如果封装到一个可迭代对象中。可以一个取一个,良好的控制!
import re ret=re.finditer('\d','ds3sy4784a') print(ret) print(next(ret)) print(next(ret).group()) print(next(ret).group()) >>> <callable_iterator object at 0x101979f60> <_sre.SRE_Match object; span=(2, 3), match='3'> 4 7