在Python中,使用re模块提供的函数,可以直接用指定的正则表达式对给定文本进行字符串的搜索、替换和分割等,也可以通过创建正则表达式对象,然后使用该对象的属性和方法来实现。搜索的结果以匹配对象的形式返回,可以利用该对象提供的属性和方法作进一步的显示和处理。[大谦Excel,dqexcel点com]
re模块
在Python中使用re模块实现正则表达式的应用。该模块提供了一系列函数,使用它们可以实现不同形式的文本查找、替换和分割等功能。
一、查找
re模块提供了4个函数来实现不同形式的查找功能,即match, search, findall和finditer函数,前两个函数返回一个满足要求的匹配对象,后两个返回所有满足要求的匹配对象。使用re模块,首先要导入该模块:
>>> import re
re.match函数
re.match函数从给定文本打头的位置开始匹配,如果匹配不成功,返回None。该函数的语法格式为:
re.match(pattern, string, flags=0)
其中各参数的含义如表7-1中所示。
表7-1 re.match函数的参数
| 参 数 | 说 明 |
|---|---|
| pattern | 进行匹配的正则表达式 |
| string | 给定的文本 |
| flags | 标记,指定正则表达式的匹配方式如是否区分大小写等 |
flags参数用来指定正则表达式的匹配方式,其取值如表7-2中所示。如果同时设置多个标记,标记之间可以用竖线连接,如re.M|re.I。
表7-2 标记设置
| 标记 | 完整写法 | 说 明 |
|---|---|---|
| re.I | re.IGNORECASE | 不区分大小写 |
| re.M | re.MULTILINE | 支持多行 |
| re.S | re.DOTALL | 使点做任意匹配,包括换行符在内的任意字符 |
| re.L | re.LOCALE | 进行本地化识别匹配 |
| re.U | re.UNICODE | 根据Unicode字符集解析字符 |
| re.X | re.VERBOSE | 支持更灵活更详细的模式,比如多行、忽略空白、加入注释等 |
如果匹配成功,re.match函数返回一个Match对象,否则返回None。
下面给定一个字符串和一个匹配规则,用re.match函数进行匹配。
>>> import re
>>> a="abc123def456"
>>> m=re.match("abc",a)
>>> m
<re.Match object; span=(0, 3), match='abc'>
从字符串a的打头位置开始匹配"abc",匹配成功,返回一个Match对象,它的值为"abc",位置是第1个字符到第3个字符。
如果给定的字符串和匹配字符串有大小写区分,例如:
>>> b="aBC123dEf456"
>>> m=re.match("abc",b)
>>> m
返回的m为空,表示匹配不成功。如果不区分大小写,使用re.I标记。
>>> m2=re.match(“abc”,b,re.I)
>>> m2
<re.Match object; span=(0, 3), match=’Abc’>
现在匹配成功,返回匹配结果"Abc"。
re.search函数
跟re.match函数不同,re.search函数在整个给定的字符串中进行查找,并返回第一个匹配成功的对象。该函数的语法格式为:
re.search(pattern, string, flags=0)
函数各参数的说明与re.match函数的相同,请参阅。
下面给定一个字符串,在整个字符串中查找"def",不区分大小写,返回查找到的第1个结果。
>>> import re
>>> a="aBC123dEf456"
>>> m=re.search("def",a,re.I)
>>> m
<re.Match object; span=(6, 9), match='dEf'>
匹配成功,返回匹配结果"dEf"。
re.findall函数
re.findall函数在给定字符串中查找正则表达式所匹配的所有子字符串,并将结果以列表的形式返回,如果匹配不成功,返回空列表。
注意:re.match和re.search函数只匹配一次,re.findall函数则找出所有匹配结果。
re.findall函数的语法格式为:
findall(pattern, string,flags=0)
其中,各参数的意义与re.match函数的相同,请参阅。
下面给定一个字符串,在整个字符串中查找"abc",不区分大小写,返回查找到的所有结果。
>>> import re
>>> a="aBC123dEf456abc789abC"
>>> m=re.findall("abc",a,re.I)
>>> m
['aBC', 'abc', 'abC']
可见,匹配成功的结果用列表的形式给出。
re.finditer函数
跟re.findall函数一样,re.finditer函数也是在给定字符串中找到正则表达式所匹配的所有子字符串。不同的是,前者将匹配结果以列表的形式给出,后者把匹配结果以迭代器的形式返回。该函数的语法格式为:
re.finditer(pattern, string, flags=0)
其中,各参数的意义与re.match函数的相同,请参阅。
下面给定一个字符串,在整个字符串中查找"abc",不区分大小写,返回查找到的所有结果。
>>> import re
>>> a="aBC123dEf456abc789abC"
>>> m=re.finditer("abc",a,re.I)
>>> m
<callable_iterator object at 0x0000000005BF0F48>
可见,re.finditer函数是将匹配结果以迭代器的形式返回的。使用for循环可以输出迭代器中的对象。
>>> for i in m:
print(i)
<re.Match object; span=(0, 3), match='aBC'>
<re.Match object; span=(12, 15), match='abc'>
<re.Match object; span=(18, 21), match='abC'>
可见,迭代器m中有3个匹配对象,for循环输出了它们的值和在给定字符串中的位置。
二、替换
所谓替换,是要在查找的基础上,用给定的对象替换匹配到的对象。使用re.sub和re.subn函数进行替换。
re.sub函数
函数的语法格式为:
re.sub(pattern, repl, string, count=0, flags=0)
其中各参数的意义为:
pattern - 进行匹配的正则表达式。
repl - 用作替换的字符串,可以是一个函数。
string – 给定的原始字符串。
count – 进行替换的最大次数,默认0表示全部替换。
flags - 指定正则表达式匹配方式的标记。
下面给定一个字符串,在整个字符串中查找"abc",不区分大小写,匹配结果全部替换为"xyz"。
>>> import re
>>> a="aBC123dEf456abc789abC"
>>> m=re.sub("abc","xyz",a,0,re.I)
>>> m
'xyz123dEf456xyz789xyz'
可见,所有匹配结果都被替换为"xyz"。
re.subn函数
re.subn函数的作用与re.sub函数的相同,只是该函数的返回值是一个元组,元组有两个值,第一个值为实现替换后的字符串,第二个值为进行替换的次数。
该函数的语法格式为:
subn(pattern, repl, string, count=0, flags=0)
其中各参数的意义与re.sub函数的相同,请参阅。
下面给定一个字符串,在整个字符串中查找"abc",不区分大小写,匹配结果全部替换为"xyz",使用re.subn函数。
>>> import re
>>> a="aBC123dEf456abc789abC"
>>> m=re.subn("abc","xyz",a,0,re.I)
>>> m
('xyz123dEf456xyz789xyz', 3)
试比较它与re.sub函数的返回值。
三、分割
re.split函数将能够匹配到的子字符串作为分隔符分割原始字符串,将分割后的结果以列表形式返回。该函数的语法格式为:
re.split(pattern, string[, maxsplit=0, flags=0])
其中各参数的意义为:
pattern - 进行匹配的正则表达式。
string – 给定的原始字符串。
maxsplit – 最大分割次数,默认值为0,表示不限次数。
flags - 指定正则表达式匹配方式的标记。
下面给定一个字符串,在整个字符串中查找"&",找到后用作分隔符对原始字符串进行分割,返回分割的结果。
>>> import re
>>> a="aBC&123dEf&456abc&789abC"
>>> m=re.split("&",a)
>>> m
['aBC', '123dEf', '456abc', '789abC']
可见,"&"找到后被用作分隔符。以列表形式返回分割后的结果。
如果只分割2次,设置maxsplit参数的值为2。
>>> m=re.split("&",a,2)
>>> m
['aBC', '123dEf', '456abc&789abC']
如果没有匹配结果,则返回原始字符串。
>>> m=re.split("%",a)
>>> m
['aBC&123dEf&456abc&789abC']
Match对象
如7.2.1小节所述,Match对象是通过re.match, re.search和re.finditer函数返回的。Match对象是进行匹配的结果,包含了与匹配有关的很多信息。使用该对象的属性和方法可以获取这些信息。
一、Match对象的属性
Match对象的属性提供很多跟匹配有关的信息,包括原始字符串、匹配表达式、匹配时指定的起始位置和终止位置等。
Match对象的属性包括:
string属性 – 原始字符串。
re属性 – 正则表达式。
pos属性 - 开始搜索位置的索引。
endpos属性 - 结束搜索位置的索引。
lastindex属性 - 最后一个捕获分组的索引。如果没有捕获分组,返回None。
lastgroup属性 - 最后一个捕获分组的别名。如果这个分组没有别名或者没有捕获分组,返回None。
下面给定原始字符串和匹配正则表达式,用re.search函数获取Match对象和它的属性值。正则表达式中有两个分组,第1个分组由数字组成,第2个分组为字母、数字等组成。
>>> import re
>>> a="aBC123dEf456abc789abC" #原始字符串
>>> m=re.search(r"(\d+)(\w+)",a) #获取Match对象m
>>> m
<re.Match object; span=(4, 10), match='123dEf'>
>>> m.string #返回m的原始字符串
'aBC&123dEf&456abc&789abC'
>>> m.re #返回m的匹配表达式
re.compile('(\\d+)(\\w+)')
>>> m.pos #进行匹配的起始位置的索引号
0
>>> m.endpos #进行匹配的终止位置的索引号
24
>>> m.lastindex #最后一个捕获分组的索引号
2
>>> m.lastgroup #最后一个捕获分组的别名,这里没有
>>>
二、Match对象的方法
使用Match对象的方法可以获取匹配对象中各分组的详细信息,包括各分组的内容、起始位置、终止位置和范围等。
Match对象的方法包括:
group([group1, …]) - 获得一个或多个分组捕获的字符串,指定多个分组时结果以元组形式返回。group1可以使用索引号也可以使用别名。索引号0代表匹配的整个子字符串;不填写参数时,返回group(0)。没有捕获到字符串的分组返回None,捕获了多次的组返回最后一次捕获的子字符串。
groups([default]) - 以元组形式返回全部分组捕获的字符串。default表示没有捕获到字符串的分组以这个值替代,默认为None。
groupdict([default]) - 返回一个字典,该字典以有别名的分组的别名为键、以该分组捕获的字符串为值。没有别名的分组不包含在内。default含义同上。
start([group]) - 返回指定的分组捕获的子字符串在string中的起始位置索引号。group默认值为0。
end([group]) - 返回指定的分组捕获的子字符串在string中的结束位置索引号(子字符串最后一个字符的索引号+1)。group默认值为0。
span([group]) - 返回捕获的子字符串的起始位置索引号和终止位置索引号组成的元组,即(start(group), end(group))。
expand(template) - 将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>, \g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的,用\g<1>0表示\1之后是字符"0 "。
下面给定原始字符串和匹配正则表达式,用re.search函数获取Match对象和它的属性值。正则表达式中有两个分组,第1个分组由数字组成,第2个分组为字母、数字等组成。
>>> import re
>>> a="aBC123dEf456abc789abC" #原始字符串
>>> m=re.search(r"(\d+)(\w+)",a) #获取Match对象
>>> m
<re.Match object; span=(4, 10), match='123dEf'>
>>> m.group(1) #获取第1个捕获分组
'123'
>>> m.group(2) #获取第2个捕获分组
'dEf'
>>> m.group(1,2) #获取第1个和第2个捕获分组
('123', 'dEf')
>>> m.groups() #获取全部捕获分组
('123', 'dEf')
>>> m.groupdict() #字典,分组别名为键,捕获的字符串为值
{}
>>> m.start(1) #第1个分组捕获字符串的起始位置索引号
4
>>> m.end(1) #第1个分组捕获字符串的终止位置索引号
7
>>> m.start(2) #第2个分组捕获字符串的起始位置索引号
7
>>> m.end(2) #第2个分组捕获字符串的终止位置索引号
10
>>> m.span(1) #第1个分组捕获字符串的位置索引号范围
(4, 7)
>>> m.span(2) #第2个分组捕获字符串的位置索引号范围
(7, 10)
>>> m.expand(r"\2\1") #用分组的编号重构字符串
'dEf123'
Pattern对象
介绍re模块时,介绍了该模块的各种函数,其中有一个重要的函数还没有介绍,它就是re.compile函数。该函数的主要作用是创建Pattern对象,即正则表达式对象。利用该对象,也可以实现字符串的查找、替换和分割。
一、创建Pattern对象
Pattern对象即编译好的正则表达式对象,使用re模块的re.compile函数进行创建。该函数的语法格式为:
re.compile(pattern[, flags])
其中,pattern为进行匹配的正则表达式字符串,flags为指定正则表达式匹配方式的标记。
下面给定原始字符串和正则表达式,用re.compile函数将正则表达式字符串编译为正则表达式对象,然后用表达式对象的match方法从原始字符串打头位置开始进行匹配。不区分大小写。
>>> import re
>>> a="aBc123def456"
>>> p=re.compile("abc",re.I)
>>> m=p.match(a)
>>> m
<re.Match object; span=(0, 3), match=’aBc’>
匹配成功,匹配子字符串为"aBc",匹配位置为第1个字符到第3个字符。
二、Pattern对象的属性和方法
使用Pattern对象提供的属性可以获取正则表达式的相关信息:
pattern属性 - 正则表达式字符串。
flags属性 - 匹配方式,用数字表示。
groups属性 – 正则表达式中分组的个数。
groupindex属性 - 以正则表达式中有别名的分组的别名为键、以该分组的编号为值的字典,没有别名的分组不包含在内。
继续使用创建Pattern对象的示例。
>>> import re
>>> a="aBc123def456"
>>> p=re.compile("abc",re.I)
>>> p.pattern
'abc'
>>> p.flags
34
>>> p.groups
0
>>> p.groupindex
{}
Pattern对象的方法跟re模块实现字符串查找、替换和分割的函数相对应,它们提供了re模块的另一种使用方式。
Pattern对象的方法如表7-3所示。
表7-3 Pattern对象的方法
| Pattern对象的方法 | 说 明 | 对应的re模块函数 |
|---|---|---|
| match(string[, pos[, endpos]]) | 从打头位置查找 | re.match(pattern, string[, flags]) |
| search(string[, pos[, endpos]]) | 从整个字符串查找第1个 | re.search(pattern, string[, flags]) |
| findall(string[, pos[, endpos]]) | 查找全部匹配结果,列表返回 | re.findall(pattern, string[, flags]) |
| finditer(string[, pos[, endpos]]) | 查找全部匹配结果,迭代器返回 | re.finditer(pattern, string[, flags]) |
| sub(repl, string[, count]) | 替换匹配结果 | re.sub(pattern, repl, string[, count]) |
| subn(repl, string[, count]) | 替换匹配结果,元组返回 | re.sub(pattern, repl, string[, count]) |
| split(string[, maxsplit]) | 匹配结果作为分隔符分割字符串 | re.split(pattern, string[, maxsplit]) |
注意:表7-3中,Pattern对象的方法跟对应的re模块函数比较,除split方法外其他方法比对应的re模块函数多两个参数,即pos参数和endpos参数,指定进行查找或替换时指定的原始字符串中的起始位置和终止位置。