re模块是python中用于文本匹配的模块,尽管不能满足所有复杂的匹配情况,但足够应付大多数的复杂字符串的分析和信息提取。
正则表达式进行文本匹配的一般流程如下所示:
正则表达式字符串(Regular Expression Pattern)经过引擎编译后,生成表达式对象(Regular Expression Object),该对象含有进行匹配所需的信息。需要做匹配的文本,逐个字符逐个字符匹配表达式对象。如果匹配成功,返回的结果将包含匹配到的字符串、分组和在文本中的索引等信息。
在介绍具体的模块属性和方法前,先了解一下必要的基本知识。
import re
pattern = re.compile(r'name')
str = 'my name is moses'
mo = re.search(pattern, str)
上面r'name中的‘r’指的是raw(原始)的意思,一般称呼这样的字符串为原生字符串。那么原始字符串有什么用处呢?看下面的例子。
import re
s = 'Hello\, world'
#pattern = re.compile(r'\\')
pattern = re.compile('\\\\')
mo = re.search(pattern, s)
print(mo.group())
正则表达式中“\”是转义字符,这就出现了反斜杠困扰。比如说你要匹配文本中的字符“\”,那么在正则表达式中就需要4个反斜杠"\\\\"。
为什么要4个斜杠呢?是这样子的,第一步,Python会将字符串“\\\\”转义为“\\”,这相当于传入re模块的是"\\",然后第二步,按照正则表达式的转义规则"\\"转义为"\"。
整个过程是很麻烦的。而原始字符串的作用呢,就是让字符串不要考虑转义符,也就相当于不做第一步动作,直接做第二步。因此原始字符串只需要写成r"\\"即可。
正则匹配默认情况下,会尽可能长的匹配出满足正则表达式对象的结果。
import re
str = 'abbbbc'
pattern = re.compile(r'ab+')
mo = re.search(pattern, str)
print(mo.group())
这里给出的正则表达式为"ab+",按理来说可以得到ab,abb,abbb,abbbb四个结果。但是运行结果是abbbb,此时满足条件的字符串最长。这就很贪心了,我们把这种匹配模式称为
贪婪模式。
有时候我们只想取满足条件的最短字符串,这个时候就要用到非贪婪模式。将上面的"ab+”改为"ab+?",得到的结果为ab,也就是最短的字符串结果。
上面讲到pattern编译为object的过程,使用了如下方法
re.compile(pattern[, flags])
其中的flags参数,即为正则表达式的匹配模式,具体如下:
re.I / re.IGNORECASE : 忽略大小写
re.S / re.DOTALL : 点任意匹配模式。使得'.'可用匹配所有字符,包括换行符
re.L / re.LOCALE : 让\w、\W、\b、\B、\s和\S依赖当前的locale
re.M / re.MULTILINE : 多行模式。指定后,'^'会增加匹配每行的开始(也就是换行符后的位置);'$'会增加匹配每行的结束(也就是换行符前的位置)
re.U / re.UNICODE : 让\w、\W、\b、\B、\d、\D、\s和\S依赖Unicode库
re.X / re.VERBOSE : 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
如果想设置多个匹配模式,可写成re.compile(pattern, re.I | re.M)的形式。
Match对象是匹配后得到的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:string: 匹配时使用的文本。
re: 匹配时使用的Pattern对象。
pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:
group([group1, …]): 获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。
groups([default]): 以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。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
search(string[,pos[,endpos]]) / re.search(pattern, string[,flags])
返回MatchObject或None
这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。
pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。
import re
pattern = re.compile(r'world')
mo = pattern.search('hello world!')
#mo = re.search(pattern, 'hello world!')
if mo:
print(mo.group())
注意这里pattern.search('hello world!')和re.search(pattern, 'hello world!')两种写法没有区别,根据爱好选择。后面的方法都有这两种写法,不再赘述。
findall(string[, pos[, endpos]]) / re.findall(pattern, string[, flags]):
返回所有匹配的List
以列表形式返回全部能匹配的字串。
import re
p = re.compile(r'\d+')
print p.findall('one1two2three3four4')
### output ###
# ['1', '2', '3', '4']
match(string[, pos[, endpos]]) / re.match(pattern, string[, flags])
返回MatchObject或None
返回结果是Match对象。pos是开始搜索的位置,默认为0。endpos是搜索的结束位置,如果endpos比pos还小的话,结果肯定是空的。也就是说只有pos 到 endpos-1 位置的字符串将会被搜索。
import re
pattern = re.compile(r'world')
mo = pattern.match('hello world!', 6)
if mo:
print(mo.group())
### output ####
# world
split(string[, maxsplit]) / re.split(pattern, string[, maxsplit])
返回由匹配分割的List
按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。
pattern = re.compile(r'\d')
mo = pattern.split('one1two2three3four4')
if mo:
print(mo)
### output ###
#['one','two','three','four','']
sub(repl, string[, count]) / re.sub(pattern, repl, string[, count])
返回替换后的字符串
使用repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用\id或\g
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。
import re
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
mo = re.sub(pattern, r'\2 \1', s) # 这里使用了分组编号
print(mo)
### output ###
# say i, world hello!
subn(repl, string[, count]) / re.sub(pattern, repl, string[, count])
返回 (替换后的字符串, 替换次数)
import re
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
mo = pattern.subn( r'\2 \1', s) # 这里使用了分组编号
print(mo)
### output ###
# ('say i, world hello!', 2)
finditer(string[, pos[, endpos]]) / re.finditer(pattern, string[, flags])
返回MatchObject的迭代器
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器
import re
p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
print m.group(),
### output ###
# 1 2 3 4
更多
dfsl
使用分组进行文本提取,具体如下:
import re
s = '更多dfsl
'
pattern = re.compile(r'')
mo = pattern.search(s)
print(mo.group(1))
(?P
具体如下
import re
s = "ip='230.192.168.78',version='1.0.0'"
pattern = re.compile(r"ip='(?P\d+.\d+.\d+.\d+).*")
mo = pattern.search(s)
print(mo.group('ip'))
import re
s = "#who#helloworld#a中文x#"
pattern = re.compile(r"[\u4e00-\u9fa5]+")
mo = pattern.search(s)
print(mo.group())
### output ###
# 中文