Python自1.5版本起增加了re模块,提供Perl风格的正则表达式模式。Python 1.5之前的版本则是通过regex模块提供Emacs风格的模式。
就其本质而言,正则表达式是一种小型的,高度专业化的编程语言。
正则表达式模式被编译成一系列的字节码,然后由C编写的匹配引擎执行。正则表达式语言相对小型和受限(功能有限),因此并非所有字符串处理都能用正则表达式完成。当然也有些任务可以用正则表达式完成,不过最终表达式会变得异常复杂。
大多数字母和字符一般都会和自身匹配。例如,正则表达式test会和字符串"test"完全匹配。(你也可以使用大小写不敏感模式,从而让这个RE匹配"Test"或"TEST")。
这个规则当然会有例外:有些字符比较特殊,它们和自身并不匹配,而是表明应和一些特殊的东西匹配,或者它们会影响到RE其他部分的重复次数。
元字符完整列表:
.^$*+?{[]\|()
- [] : 常用来指定一个字符类别,所谓字符类别就是你想匹配的一个字符集。字符可以单个列出,也可以用"-"符号分隔的两个给定字符来表示一个字符区间。例如,[abc]将匹配"a","b","c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。如果你只想匹配小写字母,那么RE应写成[a-z]。
元字符在类别里并不起作用。例如,[akm$]将匹配字符"a","k","m"或"$"中的任意一个。"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。
- ^ : 你可以用补集来匹配不在区间范围内的字符。其做法是把"^"作为类别的首个字符;其他地方的"^"只会简单匹配"^"符号本身。例如,[^5]将匹配除"5"之外的任意字符。
- \ : 也许最重要的元字符是反斜杠"\"。作为Python中的字符串字母,反斜杠后面可以加不同的字符以表示不同特殊意义。它也可以用于取消所有元字符,这样你就可以在模式中匹配它们了。
一些用"\"开始的特殊字符所表示的预定义字符集通常是很有用的,像数字集,字母集,或其他非空字符集。下列是可用的预设特殊字符:
\d 匹配任何十进制数:相当于类[0-9] \D 匹配任何非数字字符:相当于类[^0-9] \s 匹配任何空白字符:相当于类[ \t\n\r\f\v] \S 匹配任何非空白字符:相当于类[^ \t\n\t\f\v] \w 匹配任何字母数字字符:相当于类[a-zA-Z0-9_] \W 匹配任何非字母数字字符:相当于类[^a-zA-Z0-9_]
这样,特殊字符都可以包含在一个字符类中。如,[\s,.]字符类将匹配任何空白字符或","或"."。
- . : 匹配除了换行符外的任何字符,在alternate模式(re.DOTALL)下它甚至可以匹配换行。"."通常被用于你想匹配任何字符的地方。
正则表达式第一件能做的事是能够匹配不定长的字符集,而这是其他能作用在字符串上的方法所做不到的。不过,如果那是正则表达式唯一的附加功能的话,那么它就不那么优秀了。它们的另一个功能就是你可以指定正则表达式的一部分的重复次数。
- * : * 并不匹配"*" ,相反,它指定前一个字符可以被匹配零次或更多次,而不是只有一次。
像 * 这样的重复是"贪婪的";当重复一个RE时,匹配引擎会试着重复尽可能多的次数。如果模式的后面部分没有被匹配,匹配引擎将退回并再次尝试更小的重复。
- + : 表示匹配一次或更多次。请注意 * 和 + 之间的不同。 * 匹配零或更多次,所以可以根本就不出现,而 + 则要求至少出现一次。
- ? : 匹配一次或零次。你可以认为它用于标识某事物是可选的。
- {m,n} : 最复杂的重复限定符,其中m和n是十进制整数。该限定符的意思是至少有m个重复,至多有n个重复。举个例子,a/{1,3}b将匹配"a/b","a//b","a///b"。
你可以忽略m或n;因为会为缺失值假设一个合理的值。忽略m会认为下边界是0,而忽略n的结果将是上边界为无穷大。
{0,}等同于 * ,{1,}等同于+,而{0,1}则与?相同。
re模块提供了一个正则表达式引擎的接口,可以让你将REs编译成对象并用它们来进行匹配。
>>> import re
>>> p = re.compile('ab*')
>>> p
<_sre.SRE_Pattern object at 0x917ef20>
re.compile()也接受可选的标志参数,常用来实现不同的特殊功能和语法变更。
为了匹配一个反斜杠,不得不在RE字符串中写'\\\\',因为正则表达式中必须是"\\",而每个反斜杠在常规的Python字符串值中必须表示成"\\"。在REs中反斜杠的这个重复特性会导致大量重复的反斜杠,而且所生成的字符串也很难懂。
解决的办法就是为正则表达式使用Python的raw字符串表示,在字符串前加个"r",反斜杠就不会被任何特殊方式处理。
一旦有了已经编译了的正则表达式对象,就可以使用它的一些方法和属性。
- match() 决定RE是否在字符串刚开始的位置匹配
- search() 扫描字符串,找到这个RE匹配的位置
- findall() 找到RE匹配的所有子串,并把它们作为一个列表返回
- finditer() 找到RE匹配的所有子串,并把它们作为一个迭代器返回
如果没有匹配到的话,match()和search()将返回None。如果成功的话,就返回一个 _sre.SRE_Match object 实例,其中有这次匹配的信息:它是从哪里开始和结束,它所匹配的子串等等。
re模块也提供了顶级函数,如match(),search(),sub()等等。这些函数使用RE字符串作为第一个参数。
>>> print re.findall('\d+', "xiayf 1987 08 22 hello")
>>> ['1987', '08', '22']
编译标志让你可以修改正则表达式的一些运行方式。在re模块中标志可以使用两种名字,一种是全名如IGNORECASE,一种是缩写,一个字母的形式如I。多个标志可以通过按位或|标志来连接。
- DOTALL, S 使.匹配包括换行符在内的所有字符
- IGNORECASE, I 使匹配对大小写不敏感
- LOCALE, L 做本地化识别(locale-aware)匹配
- MULTILINE, M 多行匹配,影响^和$
- VERBOSE, X 能够使用REs的verbose状态
- | : 如果A和B是正则表达式,A|B将匹配任何匹配了A或B的字符串。
为了匹配字母"|",可以用|,或将其包含在字符类中,如[|]
- ^ : 匹配行首。除非设置MULTILINE标志,它只是匹配字符串的开始。在MULTILINE模式里,它也可以直接匹配字符串中的每个换行。
例如,如果你只希望匹配在行首单词"From",那么RE将用^From
>>> import re
>>> print re.search('^From', 'From Here to Etenity')
<_sre.SRE_Match object at 0xa162950>
>>> print re.search('^From', 'Reciting from Memory')
None
>>>
- $ : 匹配行尾,行尾被定义为要么是字符串尾,要么是一个换行符后面的任何位置
- \A : 只匹配字符串首。当不在MULTILINE模式,A和^实际上是一样的。然而,在MULTILINE模式里它们是不同的:A只是匹配字符串首,而^还可以匹配在换行符之后字符串的任何位置。
- \Z : 只匹配字符串尾
- \b : 单词边界。这是个零宽界定符。只用于匹配单词的词首和词尾。单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标示的。
- \B : 另一个零宽界定符,它正好和b相反,只在当前位置不在单词边界时匹配。
- 替换所有匹配的子串
用newstring替换subject中所有与正则表达式regex匹配的子串:
result, number = re.subn(regex, newstring, subject)
- 替换所有匹配的子串(使用正则表达式对象)
reobj = re.compile(regx) result, number = reobj.subn(newstring, subject)
- 字符串拆分
result = re.spilt(regex, subject)
- 字符串拆分(使用正则表达式对象)
reobj = re.compile(regex) result = reobj.split(subject)
- 将字符串中所有匹配的子串放入数组中
result = re.findall(regex, subject)
- 遍历所有匹配的子串
for match in re.finditer(regex, subject):
# match start: match.start()
# match end(exclusive): match.end()
# matched text: match.group()