在模式匹配之前,正则表达式模式必须先被编译成regex对象,由于正则表达式在执行过程中被多次用于比较,应当先对它进行预编译,从而能提升性能。其实模块函数会对已编译对象进行缓存,所以不是所有是哟过相同正则表达式模式的search()和match()都需要编译。即使这样,你仍然节省了查询缓存,和用相同字符串反复调用函数的性能开销。因此,建议都用re.compile()进行预编译。
匹配对象是在match()和search()被调用之后返回的结果。匹配对象有两个主要的方法group()和groups()
方法group()或者返回所有的匹配对象或是根据要求返回某个特定的子组
方法groups()返回包含唯一或所有子组的元组,如果正则表达式中没有子组的话,返回一个空元组。
Python中常用函数
使用match()和search()
它是re模块的函数,正则表达式对象(regex object)的方法。从字符串的开头开始对模式进行匹配,如果匹配成功就返回一个匹配对象,如果失败就返回None。匹配对象的group()方法可以用来显示那个成功的匹配。注意,必须是从开头就匹配。m = re.match('foo', ' I don\'t like the food') 此时m为None,没有匹配对象。Search()则检查字符串任意位置的地方,而不只是从开头就要匹配上。
m = re.search('foo', 'I don\'t like the food')
m.group() #得到foo
使用括号()得到子组的结果
m = re.match('(\w\w\w)-(\d\d\d)', 'abc-123')
if m is not None:
print m.group() #所有匹配部分
print m.group(1) #匹配的子组1 'abc'
print m.group(2) #匹配的子组1 '123'
print m.groups() #所有匹配的子组 ('abc','123')
m = re.match('(a(b))', 'ab')
if m is not None:
print m.group() #所有匹配部分 'ab'
print m.group(1) #匹配的子组1 'ab'
print m.group(2) #匹配的子组1 'b'
print m.groups() #所有匹配的子组 ('ab','b')
函数或方法findall()总返回一个列表,正则表达式只有一个子组时,返回子组匹配的字符串组成的列表;如果有多个子组,返回的结果是一个元组的列表,元组中的每个元素都是一个子组的匹配内容,像这样的元组(每一个成功的匹配对应一个元组)构成了返回列表中的元素。
print re.findall('(a(b))', 'ab') 返回结果[('ab','b')] 其中()内是一个元组
sub()和subn()都是将某字符串中所有匹配正则表达式模式的部分进行替换。用来替换的部分通常是一个字符串,但也可能是一个函数,该函数返回一个用来替换的字符串。subn()还返回一个表示替换次数的数字,替换后的字符串的字符串和表示替换次数的数字作为一个元组的元素返回。
print re.subn('[ae]','X','abcdef') 输出 ('XbcdXf', 2)
split()和字符串的split()相似,在每个模式匹配的地方分割字符串,你可以通过设定一个值参数(非零)来指定分割的最大次数。如果分割符没有使用由特殊符号表示的正则表达式来匹配多个模式,那re.split() and string.split()执行过程是一样的。
from os import popen
from re import split
f = popen('dir','r')
for eachLine in f.readlines():
print split('\s\s+|\t',eachLine.strip())
f.close()
ASCII字符和正则表达式特殊字符间会产生冲突。比如,特殊符号\b在ASCII中表示退格键,同时也是正则表达式的特殊符号匹配一个单词的边界,因此为了把它不以退格键看待需要使用\\b,但这样容易将问题复杂化,造成困扰。此时可以使用原始字符串,用于简化正则表达式的复杂程度。
m = re.match('\bblow','blow') #退格键不匹配
m = re.match('\\bblow', 'blow') #转义后匹配了
m = re.match(r'\bblow', 'blow') #使用原始字符串,可以匹配
程序举例
产生用于正则表达式测试的数据
#只引入用到模块的函数,而不是整个模块
from random import randint, choice
from string import lowercase
from sys import maxint
from time import ctime
fp = open('data.txt','w+')
doms = ('com', 'edu', 'net', 'org', 'gov')
#每次产生5-10行的输出randint(5,10)生成5-10之间的一个数
for i in range(randint(5,10)):
dtint = randint(0,maxint-1) #0-((2^31)-1)之间的一个数
#将数字转换为一个日期1970年1月1日后dtint秒数的日期
dtstr = ctime(dtint)
#用户名为4-7个字符
shorter = randint(4,7)
em = ''
for j in range(shorter):
em += choice(lowercase) #随机选择小写字母
#random.choice()根据指定序列,随机返回该序列中的一个元素
longer = randint(shorter,12)
dn = ''
for j in range(longer):
dn += choice(lowercase)
print '%s::%s@%s.%s::%d-%d-%d' % (dtstr, em,
dn, choice(doms), dtint, shorter, longer)
fp.write('%s::%s@%s.%s::%d-%d-%d\n' % (dtstr, em,
dn, choice(doms), dtint, shorter, longer))
fp.close
结果:
Thu Oct 22 21:13:23 1998::gjivgb@axplhnbsqtkq.com::909062003-6-12
找出数据最后的三个整型数
使用搜索
data='Thu Oct 22 21:13:23 1998::gjivgb@axplhnbsqtkq.com::909062003-6-12'
patt = '\d+-\d+-\d+'
print re.search(patt,data).group() #'909062003-6-12'
如果要使用match()匹配,就需要从字符串的开始位置就匹配
patt = '.+(\d+-\d+-\d+)' #.#用来匹配前面的任意多个字符,()用来获取我们需要的那部分数据
print re.match(patt,data).group(1) #此时返回的是3-6-12
正则表达式默认是贪心匹配的,如果正则表达式模式中使用到通配字,那它按照从左到右的顺序求值时,会尽量“抓取”满足匹配的最长字符串。.+就会从字符串的开始处抓取满足模式的最长字符,匹配Thu Oct 22 21:13:23 1998::gjivgb@axplhnbsqtkq.com::90906200,而\d+只需一位数字就可以匹配,所以它只匹配了3.此时可以使用非贪婪操作符?,它可以在*,+,?,的后面。它的作用是要求正则表达式匹配的字符越少越好。因此上述表达式可改为patt = '.+?(\d+-\d+-\d+)'
取出最后三个数中中间的那个数字
patt2 = '-(\d+)-'
m = re.search(patt2, data)
print m.group() #-6-
print m.group(1) #6 取得子组
本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。