python3 内置的 re 模块,包含了正则表达式的操作集。 re 模块的一般使用步骤如下:
- 编译正则表达式,即使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象。
- 对目标字符串进行匹配,即通过 Pattern 对象提供的一些列方法对文本进行匹配查找,获得匹配结果(Match 对象)
- 提取结果信息,即使用 Match 对象提供的属性和方法获得信息,还可以根据需要进行其他操作。
compile 函数
Compile 函数用于编译正则表达式,生成一个 Pattern 对象。一般使用形式如下:
import re
pattern = re.compile(一个正则表达式)
成功编译并构造 pattern 对象后,就可以使用 pattern 对象方法查找、替换、统计目标字符串中与正则表达式匹配的子字符串了。pattern 对象可调用的方法有:
- match 方法:从起始位置开始查找,一次匹配
- search
- fullmatch
- sub
- subn
- split
- purge
- template
- escape
- error
- findall
- finditer 事实上,这些函数不仅是对象可调用的,也是可以使用 re 模块直接调用的。
match 方法
match 方法用于在字符串起始位置进行模式匹配,若匹配则返回 Match 对象,否则返回 None。
match(pattern, string, flags=0)
# method of re module Try to apply the pattern at the start of the string, returning a match object, or None if no match was found.
match(string=None, pos=0, endpos=None, pattern=None)
# method of Pattern instance Matches zero or more characters at the beginning of the string.
下面举例说明:
''' re 模块 compile 方法与 match 方法示例'''
import re
text1 = 'sdaksfhksjdfnkfsjldhfsk234sfd65s1df55s3sdf4156sd4et489t74t6'
text2 = 'SDakufasdakru9013rgp2k;.,/,.;.t2,445,3/4l,63;lk,3;l,43'
print('运行结果:\n')
pattern = re.compile('sdak')
# <_sre.SRE_Match object; span=(0, 4), match='sdak'>
match = pattern.match(text1)
print(match)
print('---'*10)
# None
match = pattern.match(text2)
print(match)
print('---'*10)
# <_sre.SRE_Match object; span=(7, 11), match='sdak'>
match = pattern.match(text2, pos = 7)
print(match)
if match:
# sdak
print(match.group())
print('---'*10)
# re.IGNORECASE 忽略大小写
pattern = re.compile('sdak', flags = re.IGNORECASE)
match = pattern.match(text2)
if match:
# SDak
print(match.group())
print('---'*10)
运行结果:
<_sre.SRE_Match object; span=(0, 4), match='sdak'>
------------------------------
None
------------------------------
<_sre.SRE_Match object; span=(7, 11), match='sdak'>
sdak
------------------------------
SDak
------------------------------
Match 对象
match 对象是正则表达式匹配目标字符串后返回的结果对象。它可调用以下方法:
- group([group1, …])方法,用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
- start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
- end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
- span([group]) 方法返回 (start(group), end(group))。
import re
text = 'wxhh1234@qq.com中文QQ邮箱'
# 定义正则表达式,匹配目标字符串中的电子邮箱
regexstr = '\w+@\w+\.[a-z]+'
# 将正则表达式编译成 Pattern 对象
pattern = re.compile(regexstr)
# 匹配
match = pattern.match(text)
if match:
print(match.group())
print(match.start())
print(match.end())
print(match.span())
运行结果:
wxhh1234@qq.com
0
15
(0, 15)
search 方法
Search 方法用于查找字符串的任何位置,它只返回从左到右第一个匹配的结果,而不是查找所有匹配的结果。
# search 方法示例
import re
text = 'one12twothree34four'
# 设置正则表达式查找第一个数字串
regexstr = '\d+'
pattern = re.compile(regexstr)
# match 方法是从第一个字符开始匹配,这里第一个字符不是数字,则返回 None
match = pattern.match(text)
print('pattern.match:')
print(match)
print('---'*10)
# search 方法是从左往右检索,返回第一个匹配到的结果,这里返回 12
match = pattern.search(text)
print('pattern.search:')
if match:
print(match.group())
print(match.span())
运行结果:
pattern.match:
None
------------------------------
pattern.search:
12
(3, 5)
findall 与 finditer 方法
上面的 match 和 search 方法都是一次性匹配,而有时需要获取目标字符串中所有匹配的结果,这需要使用 findall 或 finditer 方法。使用形式如下:
findall(string[, pos[, endpos]])
其中,string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果,但是它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。
简单讲就是,findall 会把所有结果一次性返回,finditer 得用循环一个一个返回
import re
text = '你好wxhh1234@qq.com中文QQ邮箱'
# 定义正则表达式,匹配字符串中的中文
regexstr = u'[\u4e00-\u9fa5]+'
pattern = re.compile(regexstr)
matchlist = pattern.findall(text)
if matchlist:
print(matchlist)
else:
print('None')
print('---'*10)
matchiter = pattern.finditer(text)
if matchiter:
print(matchiter)
for m in matchiter:
print('Match result:{}, postion: {}'.format(m.group(),m.span()))
else:
print('None')
运行结果:
['你好', '中文', '邮箱']
------------------------------
<callable_iterator object at 0x00000165B601D630>
Match result:你好, postion: (0, 2)
Match result:中文, postion: (17, 19)
Match result:邮箱, postion: (21, 23)
split 方法
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次数,不指定将全部分割。
import re
text = 'a,b;;c d ,;e'
# 正则表达式,字符串前加 r,表示该字符串是 raw string。
regexstr = r'[\,\;\s]+'
pattern = re.compile(regexstr)
match = pattern.split(text)
if match:
print(match)
else:
print('None')
运行结果:
['a', 'b', 'c', 'd', 'e']
sub 方法
sub 方法用于替换。它的使用形式如下:
sub(repl, string[, count])
- repl 可以是字符串也可以是一个函数
- 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
- 如果 repl 是函数,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
- count 用于指定最多替换次数,不指定时全部替换。
import re
# 设置模式:两个英文字符或数字的分组,中间用空格隔开
text = 'Hello 123, Hello 456'
regexstr = r'(\w+) (\w+)'
repl = 'Hello World'
pattern = re.compile(regexstr)
# 使用 'Hello World' 替换 'Hello 123' 和 'Hello 456'
res = pattern.sub(repl,text)
print(res)
print('---'*10)
# 引用分组
repl = r'\2 \1'
# regexstr 第一个括号里匹配到的是 \1 ,第二个括号里匹配到的是 \2
res = pattern.sub(repl,text)
print(res)
print('---'*10)
# 指定替换次数
def func(m):
return ('hi' + ' ' + m.group(2))
print(pattern.sub(func,text))
print(pattern.sub(func,text,1))
运行结果:
Hello World, Hello World
------------------------------
123 Hello, 456 Hello
------------------------------
hi 123, hi 456
hi 123, Hello 456
贪婪模式与非贪婪模式
- 贪婪模式,指的是整个表达式匹配成功的前提下,尽可能多的匹配(使用 * ),python 里数量词默认是贪婪的;
- 非贪婪模式,指的是整个表达式匹配成功的前提下,尽可能少的匹配(使用 *? )
# demo 1
import re
text = 'abbbbbbbbbbbbccccc'
regexStr1 = 'ab*'
regexStr2 = 'ab*?'
pattern = re.compile(regexStr1)
match = pattern.match(text)
print('贪婪模式:' + match.group())
print('---'*10)
pattern = re.compile(regexStr2)
match = pattern.match(text)
print('非贪婪模式:' + match.group())
运行结果:
贪婪模式:abbbbbbbbbbbb
------------------------------
非贪婪模式:a
# demo 2
import re
text = 'aa<div>test1</div>bb<div>test2</div>cc'
regexStr1 = '<div>.*</div>'
regexStr2 = '<div>.*?</div>'
pattern = re.compile(regexStr1)
m = pattern.search(text)
print(m.group())
print('---'*10)
pattern = re.compile(regexStr2)
m = pattern.search(text)
print(m.group())
运行结果:
<div>test1</div>bb<div>test2</div>
------------------------------
<div>test1</div>