一. 简介
正则表达式又叫规则表达式,是处理字符串的强大工具。在python中通过调用re模块,可以实现正则匹配,正则表达式模式被编译成一系列的字节码,然后由C编写的匹配引擎执行
二. python常用字符含义(匹配模式)
三. re模块
1. re.match(pattern, string, flags=0) | match(string, [pos, endpos]) (这个用于编译后返回的正则表达式对象Pattern.match())
1) 作用:尝试从字符串的起始位置匹配一个模式,如果起始位置匹配成功,返回一个match对象,否则返回None
-
pattern:匹配的正则表达式
-
string:要匹配的字符串
-
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
2) 正则表达式可以包含一些可选标志修饰符来控制匹配模式。修饰符被指定为一个可选的标志,多个修饰符可以通过 | 来指定,如re.I | re.M表示对大小写不敏感和多行匹配
3) 实例
import re print(re.match('www', 'www.runoob.com').span()) #在起始位置匹配
print(re.match('com', 'www.runoob.com')) #不在起始位置匹配
运行结果为:
(0, 3)
None
为什么第一个起始位置匹配要加span()?
span()的作用是:返回一个元组包含匹配 (开始,结束) 的位置,如果不加span(),我们获得的只是一个match obj,只有加了span(),我们才能获得匹配对象的位置。不信请看:
#在命令行输出 print(re.match('www', 'www.runoob.com')) <_sre.SRE_Match object; span=(0, 3), match='www'>
print(re.match('com', 'www.runoob.com')) None
为什么第二个非起始位置匹配不加span()?
不在起始位置匹配,默认返回的None,而None对象是没有span()方法的,这时候就会报错:
import re print(re.match('com', 'www.runoob.com').span()) Traceback (most recent call last): File "<pyshell#16>", line 1, in <module> print(re.match('com', 'www.runoob.com').span()) AttributeError: 'NoneType' object has no attribute 'span'
2. re.search(pattern, string, flags=0) | search(string, [pos, endpos]) (这个用于编译后返回的正则表达式对象Pattern.search())
1) 作用:在字符串内查找匹配模式,只要找到第一个匹配则返回一个match对象,如果没有找到,则返回None
import re #不加span()返回一个match对象 print(re.search('www', 'www.runoob.com')) <_sre.SRE_Match object; span=(0, 3), match='www'> print(re.search('www', 'www.runoob.com').span()) (0, 3)
print(re.search('com', 'www.runoob.com').span()) (11, 14)
3. re.match和re.search一旦匹配成功,就会返回一个match object对象,而match object对象有以下方法:
-
group(num) num代表组号,表示匹配第num组的字符串,不写时默认是0,表示匹配整个表达式的字符串。group()也可以一次输入多个组号,如group(1, 2, 3),这种情况下它将返回一个包含那些组所对应的元组
-
groups() 返回一个包含所有小组字符串的元组,从1到所含的小组号
-
span() 返回一个元组包含匹配(开始、结束)的位置
-
start() 返回匹配开始的位置
-
end() 返回匹配结束的位置
1) 实例
import re line = "Cats are smarter than dogs" searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I) print(searchObj.group()) Cats are smarter than dogs print(searchObj.group(0)) Cats are smarter than dogs print(searchObj.group(1)) Cats print(searchObj.group(2)) smarter print(searchObj.group(1, 2)) ('Cats', 'smarter')
print(searchObj.groups())
('Cats', 'smarter')
为什么第二组匹配是 (.*?) 而不是 (.*)
我们做个试验,尝试一下 (.*)
import re line = "Cats are smarter than dogs" searchObj = re.search( r'(.*) are (.*) .*', line, re.M|re.I) print(searchObj.group()) Cats are smarter than dogs print(searchObj.group(1)) Cats print(searchObj.group(2)) smarter than print(searchObj.group(1, 2)) ('Cats', 'smarter than')
注意到group(2)的数据是不同的,这个是为什么呢?这就涉及到贪婪匹配和非贪婪匹配
贪婪匹配: 在整个表达式匹配成功的情况下,尽可能多的匹配。比如上面的 .*
.表示除换行之外的所有字符, *表示匹配前面的字符0次或无数次
非贪婪匹配:在整个表达式匹配成功的情况下,尽可能少的匹配。比图上面的 .*?
?表示匹配前面字符0次或1次
注意前面 are () .* 中,()前后是两个空格,而are之后两个空格之间有两种情况,1. "smarter than", 2. "smarter",具体选择哪种是由匹配模式决定的,当()里是贪婪匹配时,.*可以匹配smarter,可以匹配空格,可以匹配than,当()里是非贪婪模式时, .*?只会匹配smarter,因为它最多匹配一次
为什么要用前缀 r 呢?
我们知道在python中, 表示转义字符,如果需要匹配一个 本身呢?我们就要用\, 而分别对每个 进行转义,就需要用 \\
注意:如果字符串中有字符*需要匹配,可以使用*或字符集[*]
4. re.compile(pattern, [flags])
1) 作用:用于编译正则表达式,生成一个正则表达式对象(Pattern,这个Pattern不能直接实例化,必须由re.compile()进行构造),供match()和search()这两个函数使用
-
pattern:一个字符串形式的正则表达式
-
flags:编译标志位,用于控制正则表达式的匹配方式,如:是否区分大小写、多行匹配等
2) 实例1
import re #用于匹配至少一个数字 pattern = re.compile(r'd+') #从开始位置匹配 m = pattern.match('one12twothree34four') #没有匹配,返回None print(m) None #从"1"的位置开始匹配 m = pattern.match('one12twothree34four', 3, 10) #正好匹配返回一个match对象 print(m) <_sre.SRE_Match object; span=(3, 5), match='12'> print(m.group()) 12 print(m.start()) 3 print(m.end()) 5 print(m.span()) (3, 5)
实例2
import re #re.I表示忽略大小写 pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) m = pattern.match('Hello World Wide Web') #匹配成功返回一个match对象 print(m) <_sre.SRE_Match object; span=(0, 11), match='Hello World'> #返回匹配成功的整个子串 print(m.group(0)) Hello World #返回匹配成功的整个子串的索引 print(m.span(0)) (0, 11) #返回第一个分组匹配成功的子串 print(m.group(1)) Hello #返回第一个分组匹配成功的子串的索引 print(m.span(1)) (0, 5) #返回第二个分组匹配成功的子串 print(m.group(2)) World #返回第二个分组匹配成功的子串的索引 print(m.span(2)) (6, 11) #等价于(m.group(1), m.group(2), ...) print(m.groups()) ('Hello', 'World') #不存在第三个分组 print(m.group(3)) Traceback (most recent call last): File "<pyshell#67>", line 1, in <module> print(m.group(3)) IndexError: no such group
5. re.findall(pattern, string, flags=0) | findall(string, [pos, endpos])
1) 作用:遍历匹配,以列表形式返回所有能匹配的子串,如果没找到匹配的,则返回空列表
-
string:待匹配的字符串
-
pos:可选参数,指定字符串的起始位置,默认为0
-
endpos:可选参数,指定字符串的结束位置,默认为字符串的长度
2) 实例
import re #查找数字 pattern = re.compile(r'd+') result1 = pattern.findall('runoob 123 google 456') print(result1) ['123', '456'] result2 = pattern.findall('run88oob123google456', 0, 10) print(result2) ['88', '12']
6. re.finditer(pattern, string, flags=0) | finditer(string, [pos, endpos])
1) 作用:搜索string,返回一个顺序访问每一个匹配结果(match对象)的迭代器。找到匹配的所有子串,并把它们作为一个迭代器返回。
2) 实例
import re pattern = re.compile(r'd+') print(pattern.finditer('one1two2three3four4')) <callable_iterator object at 0x00000000035A8B00> for m in pattern.finditer('one1two2three3four4'): print(m) print(m.group()) <_sre.SRE_Match object; span=(3, 4), match='1'> 1 <_sre.SRE_Match object; span=(7, 8), match='2'> 2 <_sre.SRE_Match object; span=(13, 14), match='3'> 3 <_sre.SRE_Match object; span=(18, 19), match='4'> 4
7. re.split(pattern, string, [maxsplit=0, flags=0]) | split(string, [maxsplit])
1) 作用:按照能够匹配的子串将字符串分割后返回列表
-
pattern:匹配的正则表达式
-
string:要匹配的字符串
-
maxsplit:分割次数,maxsplit=1 分割一次,默认为0,不限制次数
-
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写、多行匹配等
2) 实例1
import re pattern = re.compile(r'd+') print(pattern.split('one1two2three3four4')) ['one', 'two', 'three', 'four', ''] #注意后面没有内容,是一个''字符
实例2
import re #匹配W+表示非单词字符一次或无数次 pattern = re.compile(r'W+') #用非单词字符分割 print(pattern.split('hello, world')) ['hello', 'world']
使用带括号的正则表达式则可以将正则表达式匹配的内容也添加到列表内
import re #带括号的正则表达式则可以将正则表达式匹配的内容也添加到列表内 pattern = re.compile(r'(W+)') print(pattern.split('hello, world')) ['hello', ', ', 'world']
参考文章