目录
编译正则表达式
一般步骤
re.compie
pattern对象的属性及方法
fags属性
groups属性
groupindex属性
pattern.match()方法
re.match()方法
pattern.search()方法
re.search()方法
findal()方法
pattern.findal()方法
re.findal()方法
pattern.finditer()方法
re.finditer()方法
pattern.spit()方法
re.spit()方法
pattern.sub()方法
re.sub()方法
pattern.subn()方法
re.subn()方法
继之前总结的正则表达式一些符号后,本节继续总结如何编译正则表达式以及编译后的表达式对象常用的方法/属性,还有re模块下的相关方法对比
把那些经常使用的正则表达式编译成正则表达式对象,目的是为了重复利用,这样可以提高一定的效率。编译一次之后可以多次使用,还能够将其序列化。
使用re的一般步骤是先将正则表达式的字符串形式编译为pattern实例,然后使用pattern实例处理文本并获取匹配结果(一个Match实例),最后使用Match实例获取信息进行其他操作。
re.compile(pattern, flags=0)
pattern类的工厂方法,将正则表达式pattern编译成pattern对象,并返回该对象。
参数:第二个参数flag是匹配模式,取值可以使用按位或运算符‘|’表示同时生效,比如re.I和re.M,也可以在regex字符串中指定模式,比如:
re.compile('pattern',re.I|re.M)
等价于:
re.compile('(?im)pattern')
代码示例:
import re
#将正则表达式编译成Pattern对象
pattern=re.compile(r'hello')
#使用Pattern匹配文本,获取匹配结果,无法匹配时将返回None
match=pattern.match('hello world')
if match:
#获取分组信息
print (match.group())
print (match.pos)
print (match.endpos)
pattern对象指的是通过re.compile()函数编译后得到一个正则表达式,pattern不能直接实例化,必须使用re.compile()函数进行构造。pattern对象的属性和方法如下:
>>> p = re.compile(r'\d')
>>> dir(p)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'findall', 'finditer', 'flags', 'fullmatch', 'groupindex', 'groups', 'match', 'pattern', 'scanner', 'search', 'split', 'sub', 'subn']
表示获取编译时用的匹配模式,数字形式.通过p.flags我们可以查看编译时的选项,不过它显示的不是字符而是一个整数。
代码示例:将正则表达式编译成Pattern对象
>>> p = re.compile(r'(\w+) (\w+)(?P.*)', re.DOTALL)
>>> p.flags#compile编译后用pattern对象的flags得到的是48
48
>>> re.DOTALL #直接打印类属性re.DOTALL得到的是16
>>> re.match(r'.','\nbds',16) #直接输入数字和输入类属性re.DOTALL是一样的
<_sre.SRE_Match object; span=(0, 1), match='\n'>
>>> re.match(r".","\ndb",48) #16和48是一样的效果
<_sre.SRE_Match object; span=(0, 1), match='\n'>
>>> p = re.compile(r'(\w+) (\w+)(?P.*)', 16)
>>> p.flags#compile编译后用pattern对象的flags得到的是48
48
获取正则表达式中分组的个数,也就是括号的组数。
代码示例:
>>> p = re.compile(r'(\w+) (\w+)(?P.*)', re.DOTALL)
>>> p.groups
3
以表达式中有别名的组的别名为键,其对应的编号为值的字典,没有别名的组不包含在内
代码示例:
# 将正则表达式编译成Pattern对象
>>> p = re.compile(r'(\w+) (\w+)(?P.*)', re.DOTALL)
#获取表达式中所有分组的别名和分组序号组成的字典
>>> p.groupindex
mappingproxy({'sign': 3})
match(string=None, pos=0, endpos=9223372036854775807, *, pattern=None)
函数作用:在字符串string的pos位置开始尝试匹配pattern,如果匹配成功无论是否到达结束位置endpos,都会返回一个匹配成功后的Match对象;如果匹配未成功或者pattern未匹配结束就达到endpos,则返回None。
参数说明:
string:被匹配的字符串
pos:匹配的起始位置,可选,默认为0
endpos:匹配的结束位置,可选,默认为len(string)
匹配到的Match对象,使用其group()方法取出匹配结果
代码示例:
#encoding=utf-8
import re
p = re.compile(r'\d+')
#不指定匹配区间
m1 = p.match('123abc')
if m1:
print('匹配的内容为:',m1.group())
else:
print('没有匹配的内容')
#指定匹配区间
m2 = p.match('123abc',2)
if m2:
print('匹配的内容为:',m2.group())
else:
print('没有匹配的内容')
#指定匹配区间,结束位置超过字符串长度,不会报错
m3 = p.match('123abc',2,10)
if m3:
print('匹配的内容为:',m3.group())
else:
print('没有匹配的内容')
match(pattern, string, flags=0)
函数作用:在字符串string的起始位置开始尝试匹配pattern,如果匹配成功返回一个匹配成功后的Match对象;否则返回None。
参数说明:
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,是否匹配多行等
区别:该方法与pattern.match()方法的区别在于,它不能指定匹配的区间pos和endpos
代码示例:
match=re.match('\d\s\w','1 Abs',re.I)
if match:
print ('匹配的内容为:',match.group())
else:
print ('未找到匹配内容')
search(string=None, pos=0, endpos=9223372036854775807, *, pattern=None)
函数作用:在string[pos,endpos]区间从pos处开始匹配pattern,如果匹配成功,返回匹配成功的Match对象;如果未成功,将pos加1后重新尝试匹配,直到pos=endpos时仍无法匹配则返回None。
参数说明:
string:被匹配的字符串
pos:匹配的起始位置,可选,默认为0
endpos:匹配的结束位置,可选,默认为len(string)
也就是说如果不指定pos和endpos的话,该方法会扫描整个字符串匹配到的Match对象,使用其group()方法取出匹配结果
区别:该方法与pattern.match的区别在于,match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败返回None;而search搜索整个字符串,直到知道的一个匹配
代码示例:
#encoding=utf-8
import re
#匹配多个数字,最多一个空格,0个或多个单词字符(字母和数字)
p=re.compile(r'\d+\s?\w*')
#不指定匹配区间
m1 = p.search('12 bcr123Abc123')
if m1:
print ('匹配的内容是:', m1.group())
else:
print ("正则表达式没有匹配到内容")
#指定匹配区间
m2 = p.search('12 bcr123Abc123',1,10)
if m2:
print ('匹配的内容是:', m2.group())
else:
print ("正则表达式没有匹配到内容")
#指定匹配区间,结束位置超过字符串长度
m3 = p.search('12 bcr123Abc123',3,30)
if m3:
print ('匹配的内容是:', m3.group())
else:
print ("正则表达式没有匹配到内容")
search(pattern, string, flags=0)
函数作用:扫描整个字符串并返回第一次成功的匹配对象,如果匹配失败返回None。
区别:该方法与pattern.search的区别在于,它不能指定匹配的区间pos和endpos
参数说明:
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,是否匹配多行等
代码示例:匹配abc中任一字母,一星号(*),两个数字
#encoding=utf-8
import re
m = re.search(r'[abc]\*\d{2}','c*2345')
if m:
print('匹配的内容为:',m.group())
else:
print('没有匹配的内容')
函数作用:查找字符串中所有能匹配的字符串,并以结果存于列表中,返回该列表。特殊的地方在于返回的列表中的内容,取决于正则表达式中圆括号的的出现情况,也就是分组情况:
- 当正则表达式中含有多个圆括号()时,返回列表中的元素由所有满足匹配的内容组成,但是每个元素都是由表达式中所有的圆括号匹配的内容组成的元组。而且元组中元素的个数与括号对数相同,并且字符串排放顺序和括号中出现的顺序一致(一般看左括号’(’就行,字符串的内容与每个括号内的正则表达式相对应)
>>> re.findall(r"([a-z])(\d+)","1a2b3c")
[('a', '2'), ('b', '3')]
>>> re.findall(r"([a-z])(\d+)([a-z])","a1ab2bc3")
[('a', '1', 'a'), ('b', '2', 'b')]
>>> re.findall(r"(([a-z])(\d+)([a-z]))","a1ab2bc3c")
[('a1a', 'a', '1', 'a'), ('b2b', 'b', '2', 'b'), ('c3c', 'c', '3', 'c')]
2.当正则表达式中只有一个圆括号时,返回的列表元素由所有成功匹配表达式中圆括号匹配的内容组成,并且该列表中的元素都是字符串,它的内容与括号中的正则表达式相对应。(注意:列表中的字符串只是圆括号中的内容,不是整个正则表达式所匹配的内容)
>>> re.findall(r"[a-z](\d+)","1a2b3c")
['2', '3']
当正则表示式中没有圆括号时,返回列表中的元素由所有成功匹配的子串组成
>>> re.findall(r"\d+","1a2b3c")
['1', '2', '3']
findall(string=None, pos=0, endpos=9223372036854775807, *, source=None)
函数作用:在string[pos,endpos]区间从pos下标开始查找所有满足pattern的子串,直到endpos位置结束,并以列表的形式返回查找的结果,如果未找到则返回一个空列表
参数说明:
string:被匹配的字符串
pos:匹配的起始位置,可选,默认为0
endpos:匹配的结束位置,可选,默认为len(string)。也就是说如果不指定pos和endpos的话,该方法会在整个字符串中查找满足条件的子串。
#代码示例1:正则表达式无圆括号时
#找到正则表达式匹配的前10个字母中的所有数字
pattern=re.compile(r'\d+')
match=pattern.findall('o89ne1two2three3four4',0,10)
print (match)
#代码示例2:正则表达式有1个圆括号时
#查找字符串中所有的数字子串
matchStr='adsd12343.jl34d5645fd789'
pattern=re.compile(r'.*?(\d+).*?')
result=pattern.findall(matchStr)
print (result)
总结:当正则表达式中只带有一个圆括号时,列表中的元素为字符串,并且该字符串的内容与括号中的正则表达式相对应,并且整个返回的结果都是圆括号中的内容,而不是整个正则表达式匹配的内容
代码示例3:正则表达式有多个圆括号时
#提取字符串中所有的有效的域名地址
add = 'https://www.net.com.edu//action=?asdfsd and other https://www.baidu.com//a=b'
pattern=re.compile(r'((w{3}\.)(\w+\.)+(com|edu|cn|net))')
result = pattern.findall(add)
print (result)
findall(pattern, string, flags=0)
函数作用:获取字符串中所有能匹配的字符串,并以列表的形式返回。
区别:该方法与pattern.findall的区别在于,它不能指定匹配的区间pos和endpos
参数说明:
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,是否匹配多行等
代码示例1:正则表达式无圆括号时
#匹配字符串中所有含有’oo’字符的单词
res = re.findall(r'\w*oo\w*', 'woo this foo is too')
print (res)
代码示例2:正则表达式有1个圆括号时
#获取字符串中所有的数字字符串
res=re.findall(r'.*?(\d+).*?','adsd12343.jl34d5645fd789')
print (res)
代码示例3:正则表达式有多个圆括号时
#提取字符串中所有的有效的域名地址
add = 'https://www.net.com.edu//action=?asdfsd and other https://www.baidu.com//a=b'
res = re.findall(r'((w{3}\.)(\w+\.)+(com|edu|cn|net))',add)
print (res)
finditer(string, pos=0, endpos=9223372036854775807)
函数作用:和findall函数一样,匹配字符串中所有满足的子串,只是返回的是迭代器,而不是存有所有结果的list,这个迭代器里面存的是每一个结果的匹配对象,这样可以节省空间,一般用在需要匹配大量的结果情况下。
参数说明:
string:被匹配的字符串
pos: 匹配的起始位置,可选,默认为0
endpos:匹配的结束位置,可选,默认为len(string)。也就是说如果不指定pos和endpos的话,该方法会在整个字符串中查找满足条件的子串。
代码示例:
#encoding=utf-8
import re
p = re.compile(r'[a-z]+',re.I)
for i in p.finditer('one12two34three56four'):
print(i.group())
finditer(pattern, string, flags=0)
函数作用:和findall函数一样,匹配字符串中所有满足的子串,只是返回的是迭代器,而不是存有所有结果的list,这个迭代器里面存的是每一个结果的匹配对象,这样可以节省空间,一般用在需要匹配大量的结果情况下。
参数说明:
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,是否匹配多行等
代码示例:
#匹配字符串中所有连续字母组成的子串
#encoding=utf-8
import re
for i in re.finditer(r'[A-Za-z]+','one12two34three56four'):
print(i.group())
split(string=None, maxsplit=0, *, source=None)
函数作用:分隔字符串,将字符串string用给定的正则表达式匹配的字符串进行分隔,并返回分隔后的结果列表
参数说明:
string:被匹配的字符串
maxsplit :用于指定最大分隔次数,可选,默认为0.表示全部分隔
代码示例:
#encoding=utf-8
import re
p = re.compile(r'\d+')
#不指定分割次数
print( p.split('one1two2three3four4'))
#分割3次
print( p.split('one1two2three3four4',3))
split(pattern, string, maxsplit=0, flags=0)
函数作用:分隔字符串,将字符串string用给定的正则表达式匹配的字符串进行分隔,并返回分隔后的结果list
参数说明:
pattern:匹配的正则表达式
string:被匹配的字符串
maxsplit :用于指定最大分隔次数,可选,默认为0.表示全部分隔
flags:标志位,用于控制正则表达式的匹配方式,如是否区分大小写,是否匹配多行等
代码示例1:
#encoding=utf-8
import re
#不指定分割次数
print(re.split(r'\d+','one1two2three3four4'))
#分割3次
print( re.split(r'\d+','one1two2three3four4',3))
代码示例2:切割出abcd
>>> s = "a 2 b 2 c 5 d"
>>> print( re.split(r'\s+\d\s+',s))
['a', 'b', 'c', 'd']
>>> print( re.split(r'\s+\d\s+',s,2))
['a', 'b', 'c 5 d']
>>> print( re.split(r'\s+\d\s+',s,20))
['a', 'b', 'c', 'd']
sub(repl, string, count=0)
函数作用:使用repl替换string中的每一个匹配的子串后返回替换后的字符串;
当repl是一个字符串时,可使用\id或\d
当repl是一个方法时,它必须传一个Match对象,并必须返回一个字符串用于替换(返回的字符串中不能再引用分组)
参数说明:
repl:用于替换的字符串
string:要被替换的字符串
count:替换的次数,如果为0表示替换所有匹配到的子串,如果是1表示替换1次,为2替换2次等,该参数必须是非负整数,默认为0
代码示例1:repl为字符串并使用分组引用
p=re.compile(r'(\w+) (\w+)')#注意中间有空格
s='i say, hello world!'
print (p.findall(s))
#\2,\1表示分组引用,分别代表第二个分组和第一个分组
print (p.sub(r'\2 \1',s))
分析:
"i say,hello word"
一共替换2次:
第一次替换:i say--->分组1:i 分组2:say \2 \1--->say i
say i,hello word
第二次替换:hello word
hello world--->分组1:hello 分组2:world \2 \1--->world hello
最终的替换结果: say I,world hello!
代码示例2:repl为方法时,将匹配的结果m传入方法
#encoding=utf-8
import re
p=re.compile(r'(\w+) (\w+)')#注意中间有空格
def func(m):
return m.group(1).title() +' ' + m.group(2).title()
print (p.sub(func,"i say,hello word"))
代码示例3:
#encoding=utf-8
import re
p=re.compile(r'(\w+) (\w+)')
s='i say, hello world!'
#当repl为方法时
def func(m):
print (m)
## print (dir(m))
print (m.string)
print (m.regs) #打印每个分组匹配的内容在字符串中的起始坐标,左闭右开
print (m.group()) #打印匹配到的全部内容
print (m.group(1)) #打印匹配到的第一个分组的内容
print (m.group(2)) #打印匹配到的第二个分组的内容
return m.group(1).upper()+ m.group(2).upper()
print('\n')
print (p.sub(func,s,1)) #替换一次
print('*'*40)
print (p.sub(func,s))
re.sub(pattern, repl, string, count=0, flags=0)
参数说明:
pattern:匹配的正则表达式
repl:用于替换的字符串
string:要被替换的字符串
count:替换的次数,如果为0表示替换所有匹配到的字串,如果是1表示替换1次,该参数必须是非负整数,默认为0。
flags:标志位,控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等。
代码示例1:repl为字符串
#encoding=utf-8
import re
#将手机号的后4位替换成0
tel='13549876489'
print(re.sub(r'\d{4}$','0'*4,tel))
#将代码后面的注释信息去掉
s = 'num=0 # a number'
print(re.sub(r'#.*$','',s))
代码示例2:repl为方法
使用add方法作为第二个参数,将匹配到的每个数字作为参数传入add函数,处理后将返回结果替换为相应字符串
#encoding=utf-8
import re
def add(m):
'''将匹配到的数字加10'''
return str(int(m.group())+10)
print(re.sub(r'\d+',add,'1 2 3 4 5'))
代码示例3:替换掉字符串中的空白字符
>>> re.sub(r'\s','','and \r \n \tn')
'andn'
>>> re.sub(r"[ \t\r]+","","aa 11b b22 \n \t cc")
'aa11bb22\ncc'
pattern.subn(repl, string[, count = 0])
函数作用:sub函数的用法差不多,只是它返回的是一个tuple,tuple的第一个元素为替换后的新字符串,第二个元素是替换的次数。如果想知道替换过程中到底替换了多少次,可以使用subn函数。
代码示例1:repl为字符串,去掉语句中的特殊符号
#encoding=utf-8
import re
s = "^&&today&(is%%#fine# day!"
p = re.compile(r'[^\w\s]+')
print(p.subn('',s))
代码示例2:repl参数为方法时
#encoding=utf-8
import re
print('\n')
def add(m):
'''将匹配到的数字加10'''
return str(int(m.group())+10)
print(re.subn(r'\d+',add,'1 2 3 4 5'))
re.subn(pattern, repl, string, count=0, flags=0)
代码示例:替换掉除\n外的空白字符
>>> re.subn(r"[ \t\r]+","","aa 11b b22 \n \t cc")
('aa11bb22\ncc', 4)