正则表达式(regular expressiong)是用一种形式化语法描述的文本匹配模式。模式被解释为一组指令,然后会执行这组指令,以一个字符串作为输入,生成一个匹配的字迹或者原字符串的修改版本。“正则表达式”一词在讨论中通常会简写为“regex”或者“regexp”。表达式可以包括字面文字匹配、重复、模式组、分支以及其他复杂的规则。对于很多解析问题,用正则表达式解决会比创建特殊用途的词法分析器和语法分析器容易。
正则表达式通常在涉及大量文本处理的应用中使用。例如,在开发人员使用的文本编辑程序中,常用正则表达式作为搜索模式。另外,正则表达式还是UNIX命令行工具的一个不可或缺的部分。如sed、grep和awk。很多编程语言都在语法中包括对正则表达式的支持,如Perl、Ruby、Awk和TCL。另外一些语言(如C、C++和Python)通过扩展库来对正则表达式支持。Python的re模块中使用的语法以Perl所用的正则表达式语法为基础,并提供了一些特定于Python的改进。
1. 查找文本中的模式(re.search(p,text))
re常见的用法就是搜索文本中的模式。search()函数取模式和要扫描的文本为输入,如果找到这个模式,则返回Match对象,如果未找到,search()返回为None。每个Match对象包含有关匹配的信息,包括原输入字符串、使用的正则表达式,以及模式在原字符串中出现的位置。如果Match对象为M,则M.re.pattern保存的正则表达式,M.string则为匹配的字符串,M.start()和M.end()则为匹配到的首位位置。
import re
pattern = 'this'
text = 'Does this text match the pattern?'
match = re.search(pattern, text)
s = match.start()
e = match.end()
print 'Found "%s" in:\n"%s"\nfrom %d to %d ("%s")' % \
(match.re.pattern, match.string, s, e, text[s:e])
Found "this" in:
"Does this text match the pattern?"
from 5 to 9 ("this")
match对象
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<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
2. 编译表达式(re.compile(p))
re包含一些模块机函数,用于处理作为文本字符串的正则表达式,不过对于频繁使用的表达式,编译这些表达式更为高效。compile()函数会把一个表达式字符串转换为一个RegexObject。
import re
regexes = [re.compile(p) for p in ['this', 'that']]
text = 'Does this text match the pattern?'
print 'Text: %r\n' % text
for regex in regexes:
print 'Seeking "%s" ->' % regex.pattern,
if regex.search(text):
print 'match!'
else:
print 'no match'
模块级函数会维护已编译表达式的一个缓存。不过,这个缓存的大小是有极限的,直接用已编译表达式可以避免缓存查找开销。使用已编译表达式的另一个好处是,通过在加载模块时预编译所有表达式,可以把编译工作转到应用开始时,而不是当程序响应一个用户动作时才进行编译。对于一个编译好的表达式M,M.pattern保存正则表达式。结果为:
Text: 'Does this text match the pattern?'
Seeking "this" -> match!
Seeking "that" -> no match
Seeking "this" -> match!
Seeking "that" -> no match
3. 多重匹配(re.findall(p,text))
findall()函数会返回输入中与模式匹配而不重叠的所有子串。
import re
text = 'abbaaabbbaaaa'
pattern = 'ab*'
print re.findall(pattern, text)
执行结果为:['abb', 'a', 'a', 'abbb', 'a', 'a', 'a', 'a']
finditer()会返回一个迭代器,它将生成Match实例,而不像findall()返回字符串。
import re
text = 'abbaaabbbbaaaa'
pattern = 'ab'
for match in re.finditer(pattern, text):
s = match.start()
e = match.end()
print "Found '%s' at %d:%d" % (text[s:e], s, e)
这个例子找到了ab出现了两次,Match实例显示出了他们在原字符串中的位置
Found 'ab' at 0:2
Found 'ab' at 5:7
4. 模式语法
正则表达式支持强大的模式匹配,模式可以重复,可以锚定到输入中的逻辑位置,还可以采用紧凑形式表示而不需要在模式中提过每一个字面量字符。使用所有这些特性时,需要结合字面量文本值和元字符(metacharacter),元字符是re实现正则表达式模式语法的一部分。
重复与非贪婪模式
模式中有5种表达重复的方式。如果模式后面的跟有原字符
*,这个模式会被匹配0次或者多次。如果是
+,那么这个模式至少出现1次。使用“
?”则表示要出现0或者1次。如果希望出现特定的次数,需要在模式后面使用
{m},这里的m是模式匹配需要重复的次数。最后,如果如果允许重复次数在可变范围,那么可以使用
{m,n},这里的m是重复的最小次数,n是重复的最大次数。如果省略n,表示至少出现m次,且无上限。
正常情况下,处理重复指令时,re匹配模式会利用(consume)尽可能多的输入。这种所谓的“贪心”行为可能导致单个匹配减少,或者匹配中包含了多余原先预定的输入文本。
在重复指令后面加上“?”可以关闭这种贪心行为。
字符集
字符集(character set)是一组字符,包含可以与模式中相应位置匹配的所有字符。例如:[ab]可以匹配a或者b。^在字符集的首位时,表否定,即不包含字符集中的字符。随着字符集的变大,可以使用一种更紧凑的模式,利用字符区间来定义一个字符集,其中包含一个起点和一个终点之间的所有连续的字符。如:[a-zA-Z0-9]表示匹配所有大小写字母和数字的字符。元字符“.”(点号)指模式应当匹配位置的任意单个字符。