Python中的正则表达式(2)

来源:互联网 发布:网络理财顾问 编辑:程序博客网 时间:2024/06/07 01:23

  

正则表达式的使用

 

学习过最简单的正则表达式的规则后,如何在实际中运用呢?Python中的re模块提供了正则表达式引擎的接口,允许用户将表达式编译成对象,然后再进行匹配。

 

正则表达式的编译

 

将正则表达式编译成格式对象,此对象含有不同的操作函数,如查找或子串替换等。

>>> import re

>>> p = re.compile('ab*')

>>> print p

<_sre.SRE_Pattern object at 0x...>

Re.compile()也可以接受一个可选的参数flag,来选择不同的特殊功能和语法变体。我们先运行一个例子,再来讲解flag的设定:

>>> p = re.compile('ab*', re.IGNORECASE)

将正则表达式样式作为一个字符串传递给re.compile(),这是由于正则表达式不是Python的核心功能,所以也没有它的特殊语法(有些程序根本用不到正则表达式的功能,因而没有必要将它放进核心语法中),但是re模块作为C语言的扩展被包含到Python的模块中,类似的还有socket或zlib模块。

将正则表达式样式设计为字符串可以使Python语言更加简单,但是它有一个缺点,将在下一节讲解。

反斜杠\问题

如前所述,正则表达式使用反斜杠来表明特殊形式或取消特殊意义,而Python在字符串中同样使用反斜杠来实现相同意图,从而带来了冲突。

 

比如说你想写出一个正则表达式样式来匹配LaTeX中的\section,首先必须写出相应的样式,然后必须在每一个反斜杠前再加一个反斜杠来,如\\section,这个结果将传递给re.compile。然而,为了表示这是一个Python的字符串,每一个反斜杠必须再加一个反斜杠!

 

字符状态\section想要匹配的字符\\section为re.compile()去掉反斜杠“\\\\section”再加一个反斜杠来表明它是一个字符串而非有特殊意义的单词

 

简而言之,对了匹配一个无任何特殊意义的反斜杠,必须为正则表达式样式写上\\\\,因为正则表达式必须为\\,而Python字符串中的每一个无特殊含义的反斜杠都必须以\\来代替。在正则表达式中,使用反斜杠的情况常常碰见,这将导致无数多数的反复输入反斜杠,从而造成最终的字符串难于理解。

解决方法是使用Python的未转义的字符串声明:在以r为前缀的字符串中,反斜杠解除特殊含义,如r"\n"是一个包含两个字符的字符串,而"\n"则是一个字符表示换行。所以在Python代码中要使用这种表示方法来书写正则表达式。

正则表达式的样式对应的未经转义的字符串“ab*”r”ab*”“\\\\section”r”\\section”“\\w+\\s+\\s”r”\w+\s+\1”

匹配

 

当你有一个表示正则表达式的对象时,应当如何使用?样式对象有不同的方法和属性,这里只列出了最为常用的几个,包含全部方法和属性的列表请参考re的帮助文档。

 

方法或属性用途match()检查是否在字符串的开始处匹配search()在字符串中扫描并寻找匹配的位置findall()寻找所有匹配的子串,并将结果返回到一个列表中finditer()寻找所有匹配的子串,并将它们作为迭代器返回

如果没有匹配成功,则match()和search()返回None;如果成功,将返回一个MatchObject对象,包含了匹配开始和结束的信息、匹配的子串等等。

 

可以通过re模块来学习匹配的使用。如果你的系统安装有Tkinter,也可以查看Tools/scripts/redemo.py,它是Python发行版中包含的一个演示程序,允许你输入正则表达式和字符串并进行匹配。该演示程序在进行调试复杂的正则表达式程序时非常有用。Phil Schwartz的Kodos也是一个用于正则表达式开发和测试的交互式工具。

 

本文档使用Python标准的解释器来完成实例。首先,打开Python解释器,导入re模块,对正则表达式进行编译:

Python 2.2.2 (#1, Feb 10 2003, 12:57:01)

>>> import re

>>> p = re.compile('[a-z]+')

>>> p

<_sre.SRE_Pattern object at 0x...>

 

现在你可以针对正则表达式[a-z]+尝试匹配不同的字符串。一个空串肯定不会匹配,因为+表示匹配一个或多个,这种情况下调用match()应当返回None,这时Python解释器不会有任何输出,你可以通过显式的打印出匹配的结果来查看。

>>> p.match("")

>>> print p.match("")

None

 

接着来尝试一个可以匹配的字符串,这里match()将返回一个MatchObject,你可以将这个对象存储在变量中以便以后使用。

>>> m = p.match('tempo')

>>> print m

<_sre.SRE_Match object at 0x...>

 

可以请求MatchObject来查看匹配信息,它也包含不同的方法和属性,最重要的有:

 

方法或属性

用途

group()

返回匹配的字符串

start()

返回匹配的开始位置(下标)

end()

返回匹配的结束位置

span()

返回一个元组,它包含匹配的(开始,结束)的位置

尝试以下方法将阐明上面这些方法的意思:

>>> m.group()

'tempo'

>>> m.start(), m.end()

(0, 5)

>>> m.span()

(0, 5)

 

由于match()只检查字符串的起始位置,start()一定为0,但search()方法将遍历整个字符串,所以匹配可能不在起始位置。

>>> print p.match('::: message')

None

>>> m = p.search('::: message') ; print m

<_sre.SRE_Match object at 0x...>

>>> m.group()

'message'

>>> m.span()

(4, 11)

 

在实际的程序中,最常用的做法是将MatchObject存储在变量中,然后查检是否为None,例如:

p = re.compile( ... )

m = p.match( 'string goes here' )

if m:

    print 'Match found: ', m.group()

else:

    print 'No match'

 

两个成员函数将返回所有的匹配,其中一个是findall(),它返回匹配字符串的列表:

>>> p = re.compile('\d+')

>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')

['12', '11', '10']

 

findall()必须在返回结果前创建整个列表,finditer()函数返回MatchObject对象序列的迭代器:

>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')

>>> iterator

<callable-iterator object at 0x401833ac>

>>> for match in iterator:

...     print match.span()

...

(0, 2)

(22, 24)

(29, 31)