现在的位置: 首页 > 综合 > 正文

Python中的正则表达式(1)

2013年08月15日 ⁄ 综合 ⁄ 共 2694字 ⁄ 字号 评论关闭
文章目录

 

写这个系列是为了整理在Python中学习正则表达式的知识。其实在Linux Shell、PHP以及Qt的学习中都接触过正则表达式,但是由于笔记做得不好,所以经常到了使用的时候翻来翻去,很是麻烦,所以把知识梳理一下。本文主要翻译自Python标准库手册中的指南,但是没有逐字句地翻译,它比标准库中的re模块相应介绍要简单一些,也更容易看懂。

----------------------------------

正则表达式入门

本文档介绍使用Python中的re模块实现正则表达式,它比Python库手册中的相应章节相对容易一些。

引言

Re模块在Python1.5中加入,它提供了一个Perl风格的正则表达式功能。更早版本的Python使用的是regex模块,它提供的是Emacs风格的匹配。在Python2.5中,regex模块被移除。

 

正则表达式(Regular expression,又称为RE、regexe或regex pattern)是一个小巧、高度特化的编程方法,它内嵌在Python中,通过re模块实现。使用这个方法可以匹配特定格式的字符串,包括英语句子、电子邮件地址、TeX命令等等,可以检查字符串是否符合该格式,或在字符串中寻找符合该格式的子串,也可以按照格式修改或分割字符串。

 

 

正则表达式的“格式”(pattern)在运行时被由C语言写成的匹配引擎转换成字节码。对于高级应用,应当注意该引擎如何产生给定的正则表达式,并用特定方式书写该表达式以产生更高效的字节码。不过,本文档不涉及优化的问题,因为这需要对匹配引擎的内部工作原理有较好的理解。

 

正则表达式小巧且严格,所以不是所有的字符串处理都要使用它;有些问题用正则表达式可以解决,但会让问题变得复杂。在这些情况下,就不要使用正则表达式处理。尽管使用Python编写的代码比精巧设计的正则表达式慢,但它更易于理解。

 

简单的格式

 

我们从最简单的正则表达式开始学习。由于它主要用来处理字符串,我们将首先学习最普遍的情况:匹配字符。计算机科学以正则表达式为基础,关于它的详细解释可以参考关于书写编译器的几乎任何课本。

 

匹配字符

 

大多数字母和符号可以匹配自身,可以将匹配模式选择为大小写敏感或不敏感,详细内容见后。

 

这条规范有一个例外:有一些字符是特殊的“元字符”,不能匹配自身,它们表示非常规的意思,或者能够通过重复或者改变其意思影响正则表达式的其他成分。本文档专注于讨论不同的元字符及其含义。

 

下面是这些元字符,它们的意思该在本文以后的部分加以介绍。

. ^ $ * + ? { } [ ] \ | ( )

 

首先来看[和]。它们用来表示一个字符的集合,集合内的任意一个字符都可以参与匹配,其中字符可以单独列出来,或者用-来表示范围。例如,[abc]将匹配其中的任何一个字符a、b或c,它等同于用范围表示的[a-c]。如果匹配任何小写字母,可以写成[a-z]。

 

在[]中的元字符不起作用。如[akm$]将匹配a、k、m和$:$虽然是一个元字符,但是在这个集合中失去了特殊意义。

 

可以通过取补的方式匹配不在集合中的字符,方法是在该集合内的最前面加^,如果加在整个集合的前面则会匹配^。例如,[^5]将匹配除了5的任何字符。

 

最常用的元字符是反斜杠\。在Python中,字符前加\表示特殊含义;它也可以用于元字符前表示去除元字符的特殊含义。例如,如果试图匹配[或\,可以分别通过\[和\\来实现。

 

一些特殊序列以\开始,表示一些常用的预定义字符串,如下所示:

 

\d

十进制数字,相当于[0-9]

\D

非十进制数字,相当于[^0-9]

\s

空白字符,相当于[\t\n\r\v]

\S

非空白字符,相当于[^\t\n\r\f\v]

\w

字母+数字,相当于[a-zA-Z0-9]

\W

非字母非数字,相当于[^a-zA-Z0-9]

这些特殊序列可以在集合中使用。如[\s,.]匹配任何空白字符、,或者.。

 

本节中最后一个元字符是.,它匹配除新行外的任何字符(在可选用的模块(re.DOTALL)中也可以匹配新行)。当试图匹配任何字符时使用.。

 

多次匹配

 

匹配不同的字符集合是字符串中的函数无法完成而正则表达式可以完成的第一件事,但如果仅仅如此,正则表达式还显得功能简陋。它另外一个功能是可以匹配特定次数的字符。

 

多次匹配的第一个元字符是*,它不是去匹配字符本身,而是表示前一个字符可以匹配0次或多次。例如ca*t将匹配ct(0次)、cat(1次)、caaat(3次)或更多。由于C语言中整型长度的限制,正则表达式的匹配引擎内部规定不能超过20亿次的匹配,当然你可能并没有足够的内存去存储这么长的字符串,所以不用理会这个限定。

 

*的匹配是“贪婪”的:当匹配时,引擎会试图匹配更多次的字符;如果在较多次数下的匹配不成功(格式中的下一部分不能匹配时),才会试图匹配较少的重复次数。

 

逐步讲解的例子会使这种设计看上去合理。考虑a[bcd]*b,它匹配以a开始,中间含有0次或多次的b、c或者d,并最终以b结束。在字符串abcbd中的匹配过程如下:

步骤 已匹配 说明
1 a a存在于格式中。
2 abcbd 引擎匹配了[bcd]*,试图匹配尽量多次数,从而达到了字符串尾。
3 匹配失败 引擎试图匹配b,但当前位置为字符串的串尾,所以匹配失败。
4 abcb 回头重新匹配,使[bcd]*匹配次数在上次匹配的基础上减1。
5 匹配失败 再次试图匹配b,但是当前位置为最后一个字符d,匹配失败。
6 abc 回头再次重新匹配,这次[bcd]*只匹配到bc。
7 abcb

尝试匹配b,这次当前位置上为b,匹配成功。

到达正则表达式的结尾时,匹配abcb成功。以上过程表明“贪婪匹配”如果失败,则会一次重新匹配尽可能多次的格式,直到尝试匹配0次[bcd]*,如果在0次匹配的情况下后续字符依然无法匹配,则字符匹配失败。

 

另外一个重复匹配的元字符是+,它匹配一次或者多次。注意*和+的区别。

 

另外,?表示匹配0次或1次,可以把它想像成某种可选择性的场合,如home-?brew可以匹配homebrew或home-brew。

 

最常用的匹配次数表达式为{m,n},其中m和n为十进制数字,表示最少重复m次最多重复n次。例如a/{1,3}b可以匹配a/b、a//b和a///b,而对a////b不能匹配。M和n中的一个可以省略掉:省略掉m表示最少匹配0次,省略掉n表示最多匹配无穷次(实际上是20亿次)。

 

很容易看出{0,}与*意义相同,类似地,{1,}与+、{0,1}与?意义都相同。这种情况下用单个字符更容易书写,可读性也更好。

抱歉!评论已关闭.