python re正则表达式说明文档

来源:互联网 发布:网络水军兼职 编辑:程序博客网 时间:2024/06/02 04:42

这个文档是一个关于用Python中的re模块来使用正则表达式的教程。

1、序言

re 模块在Python1.5中被加入,并且提供了Perl类型的正则表达式模式。较早的Python版本用的是regex模块,它提供Emacs类型模式。 Emacs类型模式可读性差并且没有提供很多特性,因此当我们写新的代码的时候没有必要去使用regex模块,尽管你可能会碰到一些使用了它的老代码。

正 则表达式本质上是一个很小的且高度专用的程序语言,它嵌入在Python中且通过re模块可用。在使用这个小的语言的时候,你要为你想要匹配的可能的字符 串指定规则;要匹配的字符串可以是英语句子,或e-mail地址,或TeX命令,或你喜欢的任何东西。你可问问题如“这个字符串匹配这个模式吗?”,呀“ 在这个字符串中有与这个模式匹配的吗?”。你可以使用正则表达式去修改一个字符串或用不同的方法分离它。

正则表达式模式被编译成连续的字 节码,这些字节码然后被用C写成的匹配引擎执行。关于高级的使用,必须要仔细关心这个引擎如何去执行一个给定的正则表达式和你写怎样的正则表达式它所产生 的字节码运行的更快。这篇文档不涉及优化,因为它要求你对匹配引擎的内部组织有一个好的理解。

正则表达式语言是一个相对小而有限,因此不 是所有的字符串处理任务都可以用正则表达式来完成。这其中虽然有一些任务可以用正则表达式来完成,但这个表达式是非常复杂的。这种情况下,更好的方法是写 Python代码来处理,尽管Python代码比精巧的正则表达式执行的慢,但它更易理解。

2、简单模式

我们将以学习最简单的正则表达式作为开始。因为正则表达式用于处理字符串,所以我们将以最通常的任务:匹配字符 作为开始。

2.1、匹配字符

大部分的字母和字符都将只匹配它们自身。例如正则表达式test将正确地匹配字符串“test”(你也可以使用大写不敏感模式使之匹配”Test”或”TEST”)。

大部分的字母和字符都将只匹配它们自身,这个规则也有例外;有些字符是专用的,不与自身匹配。相反,它们表示本身意义之外的东西将被匹配,或者通过重复它们来影响正则表达式的其它部分。这个文档的大部分是专门讨论各种元字符和它们的作用。

下面是元字符的完整列表;它们的意义将在文档的其余部分讨论。
. ^ $ * + ? { [ ] \ | ( )
我们首先关注的元字符是”[“和”]”。 它们被用来指定一类字符,是一套你想去匹配的字符。字符可以分别列出,或使用两个字符中间用”-“分离来表示一定范围的字符。例如,[abc]将匹 配”a”,”b”,或”c”中的任一个;这与[a-c]是一样的作用,[a-c]指定了要匹配的字符范围。如果你只想匹配小写字母,你的正则表达式应是 [a-z]。

元字符在类别中是不活动的。例如,[akm]"a","k","m","”中的任一个,”$”通常是一个元字符,但是在字符类别中它脱离它的特殊性。

通过补充设置,你可以匹配不在一个范围内的字符。这可通过在字符类别中包括一个”^”作为首字符;例如,[^5]将匹配除了”5”以外的任何字符。

也许最重要的元字符是反斜杠”\”。如同Python字面上的字符串,反斜杠后可跟不同的字符去表示不同的特殊序列。它也被用来避免所有的元字符以便你仍然可以按模式匹配它们;例如,如果你需要匹配”[“或”\”,你可以在它们的前面加上一个反斜杠以消除它们特别的意思:[或\。

一些以”\”开始的特殊序列代表预定义一套字符,它们通常是有用的,诸如一套数字,一套字母或一套任何东西(不是空白)。下面的预定义的特殊序列是有效的:

\d 匹配任何十进制的数字,等同于[0-9]
\D 匹配任何非数字字符,等同于[^0-9]
\s 匹配任何空白字符,等同于[ \t\n\r\f\v]
\S 匹配任何非空白字符,等同于[^ \t\n\r\f\v]
\w 匹配任何字母数字字符,等同于[a-zA-Z0-9_]
\W 匹配任何非字母数字字符,等同于[^a-zA-Z0-9_]

这些序列可以被包括在一个字符类别中。例如, [\s,.]是一个字符类别,它将匹配任何空白字符,或”,”或”.”。

最后讨论的元字符是.。它匹配除了换行符的任何东西,这有一个候补的方法(re.DOTALL)匹配换行符。”.”经常用于在你想匹配任何字符时。

2.2、重复

我们要关注的这第一个用于重复的元字符是不能匹配字面意义上的”*”;相反,它指定前面的字符能够被匹配0次或更多次。
例如,ca*t将匹配”ct”(0个”a”字符),”cat”(1个”a”),”caaat”(3个”a”字符)等等。

另一个重复操作的元字符是+,它匹配一次或多次。+要求其前的字符至少要出现一次。例如,ca+t将匹配”cat”(1个”a”),”caaat”(3个”a”),但是不匹配”ct”。

下面是?,它表示匹配一次或0次。例如,home-?brew将匹配”homebrew”或”home-brew”。

最复杂的是{m,n} ,m和n是十进制整数。它们代表最少重复m次,并且最多重复n次。例如,a/{1,3}b将匹配”a/b”,”a//b”,和”a///b”。它不匹配”ab”,因为没有斜杠,也不匹配”a////b”,因为有个斜杠。
你可以省略m或n,省略m将被认为最小为0,省略n将意味上限无穷大。

3、使用正则表达式

现在我们已经了解一些简单的正则表达式,我们在Python中如何使用它们呢?re模块提供了一个正则表达式引擎的接口,让你把正则表达式编译成对象然后用它们执行匹配。

3.1、编译正则表达式

正则表达式被编译成RegexObject实例,它有关于各种操作的方法,如为匹配模式搜索或执行字符串替换。

import re
p = re.compile(‘ab*’)
print p

re.compile()也接受一个可选的标志参数,用来使各种特别的特性和语法变种起作用。下面是一个简单的例子:

p = re.compile(‘ab*’, re.IGNORECASE)
正则表达式被作为一个字符串传递给re.compile()。正则表达式被作为字符串处理是因为它不是核心Python语言的一部分,并且没有为表示它们而创建专门的语法。相反,re模块仅是一个被Python所包括的C扩展模块,就象socket或zlib模块。

3.2、反斜杠的麻烦

如 前所述,正则表达式使用反斜杠来标识特殊的形式或允许特别的字符被使用而避开它们的特殊意义。但这在Python中是很麻烦的。例如你想写一个正则表达式 去匹配字符串”\section’,那么正则表达式应是”\section”。然而在Python中,这个表达式要作为字面意义上的字符串传递给 re.compile(),则应写成”\\section”。这样很难理解,解决的办法是使用r前缀,如r”\section”来表示字面意义上的 字符串。

3.3、执行匹配

一旦你有了一个代表已编译的正则表达式的对象时,你用它来做什么呢?正则表达式对象实例有一些方法和属性。下面是其中最重要的:

match() 确定正则表达式是否匹配字符串的开头
search() 扫描字符串以查找匹配
findall() 找到所有正则表达式匹配的子字符串,并把它们作为一个列表返回
finditer() 找到所有正则表达式匹配的子字符串,并把它们以指示器的形式返回

match()和search()在没有发现匹配时返回None。如果匹配成功,一个MatchObject实例被返回,其中包含的匹配信息有:哪开始哪结束,匹配的子字符串等等。

你 可以通过交互式的试验使用re模块来学习这个。如果你有一个有效的Tkinter,你可能想关注Tools/scripts/redemo.py,这是一 个包含在Python发行版中的演示程序。它允许你输入正则表达式和字符串,并且显示正则表达式是否匹配。redemo.py在试图调试一个复杂的正则表 达式时可能是十分有用的。我们的文档将使用标准的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 80c3c28>
现在,现在你可以试着用正则表达式[a-z]+去匹配不同的字符串。空字符串不能匹配,因为+意味着一个或多个重复,这种情况下match()将返回None,它将使解释器什么都不输出。你也可以显示的打印match()的结果来让这个更清楚。
p.match(“”)
print p.match(“”)
None
现在,让我们试着匹配一个字符串,如”tempo”。这种情况下,match()将返回一个MatchObject,因此你可以存储这个结果到一个变量中以备后用。
m = p.match( ‘tempo’)
print m
<_sre.SRE_Match object at 80c4f68>

现在,你可以查询MatchObject以获取关于匹配字符串的信息。MatchObject实例也有一些方法和属性;最重要的几个如下:

group() 返回通过正则表达式匹配到的字符串
start() 返回成功匹配开始位置
end() 返回成功匹配结束位置
span() 返回包含成功匹配开始和结束位置的元组

试一下这些方法将很快清楚它们的意思:

m.group()
‘tempo’
m.start(), m.end()
(0, 5)
m.span()
(0, 5)

因为match方法只检查正则表达式是否匹配字符串的开头,所以start()总是返回0值。但是,RegexObject实例的search方法要扫描整个字符串,这种情况下,成功匹配的开头位置不一定会是0值。

print p.match(‘::: message’)
None
m = p.search(‘::: message’) ; print m

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’

有两个RegexObject的方法返回关于模式的所有的匹配。findall()返回所匹配的字符串的一个列表:

p = re.compile(‘\d+’)
p.findall(‘12 drummers drumming, 11 pipers piping, 10 lords a-leaping’)
[‘12’, ‘11’, ‘10’]

finditer()方法返回一个作为指示器的MatchObject实例的序列。

iterator = p.finditer(‘12 drummers drumming, 11 … 10 …’)
iterator

for match in iterator:
… print match.span()

(0, 2)
(22, 24)
(29, 31)

3.4、模块级函数

你 是非得要产生一个RegexObject,然后调用它的方法;re模块也提供了顶级的函数来调用match(),search(),sub()等等。这些 函数使用与RegexObject方法相应的参数,使用正则表达式字符串作为它们的第一个参数,并且仍然返回None或MatchObject实例。

print re.match(r’From\s+’, ‘Fromage amk’)
None
re.match(r’From\s+’, ‘From amk Thu May 14 19:12:10 1998’)

隐藏在下面的是这些函数简单地为你产生一个RegexObject并调用它的适当的方法。它们也把被编译了的对象存储在缓存中,以便于以后调用相同的正则表达式更快。

你 是使用模块级的函数还是自己得到RegexObject并调用它的方法呢?这个选择依赖于正则表达式被使用的频度,和你个人的代码风格。如果正则表达式仅 使用在代码中的一处,那么模块级函数或许更方便。如果一个程序包含了大量的正则表达式,或在不同的位置要重复使用,那么在一处集中所有的定义和提早在代码 的一部分中编译所有的正则表达式是值得的。

3.5、编辑标志

编辑标志让你修改正则表达式的一些工作方式。在re模块中标志两种名字都是有效的,长名如IGNORECASE,短名即一个字母如I。可以通过按位或(|)来指定多重标志。例如,re.I|re.M设置I和M标志。

下面是有效标志及说明:

I
IGNORECASE
说明:执行不区分大小写的匹配

L
LOCALE
说明:根据当前的场所使用\w,\W,\b,\B。
场 所是C库的一个特性,它是为了在考虑到不同的语言差异时帮助写程序。例如,如果你在处理一个法国文本,你可能想去写\w+来匹配单词,但是\w仅匹配字符 类别[A-Za-z];它不将匹配”é” 或 “ç”. 如果你的系统已恰当的配置并且法语场所已选择,某个C函数将告诉程序”é”也被考虑为一个字母。 在编译正则表达式时设置LOCALE标志将导致编译的结果对象为\w使用C函数,这是较慢的,但能如你所愿的使用\w+去匹配法文。

M
MTLTILINE
说明:多行匹配
针对”^”,表示”^”除了匹配字符串的开始位置,也匹配 ’\n’ 或 ’\r’ 之后的位置;
针对”""”除了匹配输入字符串的结束位置,也匹配 ’\n’ 或 ’\r’ 之前的位置

S
DOTALL
说明:使得”.”专用字符匹配任何字符,包括换行符;没有这个标志,”.”将匹配除了换行符以外的任何字符。