现在,让我们试着用它来匹配一个字符串,如 "tempo"。这时,match() 将返回一个 MatchObject。因此你可以将结果保存在变量里以便后面使用。
现在你可以查询 `MatchObject` 关于匹配字符串的相关信息了。MatchObject 实例也有几个方法和属性;最重要的那些如下所示:
| 方法/属性 | 作用 |
| group() | 返回被 RE 匹配的字符串 |
| start() | 返回匹配开始的位置 |
| end() | 返回匹配结束的位置 |
| span() | 返回一个元组包含匹配 (开始,结束) 的位置 |
试试这些方法不久就会清楚它们的作用了:
group() 返回 RE 匹配的子串。start() 和 end() 返回匹配开始和结束时的索引。span() 则用单个元组把开始和结束时的索引一起返回。因为匹配方法检查到如果 RE 在字符串开始处开始匹配,那么 start() 将总是为零。然而, `RegexObject` 实例的 search 方法扫描下面的字符串的话,在这种情况下,匹配开始的位置就也许不是零了。
#!python
>>> print p.match('::: message')
None
>>> m = p.search('::: message') ; print m
<re.MatchObject instance at 80c9650>
>>> m.group()
'message'
>>> m.span()
(4, 11)在实际程序中,最常见的作法是将 `MatchObject` 保存在一个变量里,然后检查它是否为 None,通常如下所示:
#!python
p = re.compile(
)
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'
两个 `RegexObject` 方法返回所有匹配模式的子串。findall()返回一个匹配字符串行表:
#!python
>>> p = re.compile('"d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']findall() 在它返回结果时不得不创建一个列表。在 Python 2.2中,也可以用 finditer() 方法。
#!python
>>> 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)
你不一定要产生一个 `RegexObject` 对象然後再调用它的方法;re 模块也提供了顶级函数调用如 match()、search()、sub() 等等。这些函数使用 RE 字符串作为第一个参数,而後面的参数则与相应 `RegexObject` 的方法参数相同,返回则要么是 None 要么就是一个 `MatchObject` 的实例。
#!python
>>> print re.match(r'From"s+', 'Fromage amk')
None
>>> re.match(r'From"s+', 'From amk Thu May 14 19:12:10 1998')
<re.MatchObject instance at 80c5978>Under the hood, 这些函数简单地产生一个 RegexOject 并在其上调用相应的方法。它们也在缓存里保存编译後的对象,因此在将来调用用到相同 RE 时就会更快。
你将使用这些模块级函数,还是先得到一个 `RegexObject` 再调用它的方法呢?如何选择依赖于怎样用 RE 更有效率以及你个人编码风格。如果一个 RE 在代码中只做用一次的话,那么模块级函数也许更方便。如果程序包含很多的正则表达式,或在多处复用同一个的话,那么将全部定义放在一起,在一段代码中提前编译所有的 REs 更有用。从标准库中看一个例子,这是从 xmllib.py 文件中提取出来的:
#!python
ref = re.compile(
)
entityref = re.compile(
)
charref = re.compile(
)
starttagopen = re.compile(
)我通常更喜欢使用编译对象,甚至它只用一次,but few people will be as much of a purist about this as I am。
编译标志让你可以修改正则表达式的一些运行方式。在 re 模块中标志可以使用两个名字,一个是全名如 IGNORECASE,一个是缩写,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同样的字母;例如 re.VERBOSE的缩写形式是 re.X。)多个标志可以通过按位 OR-ing 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
这有个可用标志表,对每个标志後面都有详细的说明。
| 标志 | 含义 |
| DOTALL, S | 使 . 匹配包括换行在内的所有字符 |
| IGNORECASE, I | 使匹配对大小写不敏感 |
| LOCALE, L | 做本地化识别(locale-aware)匹配 |
| MULTILINE, M | 多行匹配,影响 ^ 和 $ |
| VERBOSE, X | 能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂 |
I
IGNORECASE
使匹配对大小写不敏感;字符类和字符串匹配字母时忽略大小写。举个例子,[A-Z]也可以匹配小写字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。这个小写字母并不考虑当前位置。
L
LOCALE
影响 "w, "W, "b, 和 "B,这取决于当前的本地化设置。
locales 是 C 语言库中的一项功能,是用来为需要考虑不同语言的编程提供帮助的。举个例子,如果你正在处理法文文本,你想用 "w+ 来匹配文字,但 "w 只匹配字符类 [A-Za-z];它并不能匹配 "é" 或 "ç"。如果你的系统配置适当且本地化设置为法语,那么内部的 C 函数将告诉程序 "é" 也应该被认为是一个字母。当在编译正则表达式时使用 LOCALE 标志会得到用这些 C 函数来处理 "w 後的编译对象;这会更慢,但也会象你希望的那样可以用 "w+ 来匹配法文文本。
M
MULTILINE
(此时 ^ 和 $ 不会被解释; 它们将在 4.1 节被介绍.)
使用 "^" 只匹配字符串的开始,而 $ 则只匹配字符串的结尾和直接在换行前(如果有的话)的字符串结尾。当本标志指定後, "^" 匹配字符串的开始和字符串中每行的开始。同样的, $ 元字符匹配字符串结尾和字符串中每行的结尾(直接在每个换行之前)。
S
DOTALL
使 "." 特殊字符完全匹配任何字符,包括换行;没有这个标志, "." 匹配除了换行外的任何字符。
X
VERBOSE
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空白符被忽略,除非该空白符在字符类中或在反斜杠之後;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写入 RE,这些注释会被引擎忽略;注释用 "#"号 来标识,不过该符号不能在字符串或反斜杠之後。
举个例子,这里有一个使用 re.VERBOSE 的 RE;看看读它轻松了多少?
#!python
charref = re.compile(r"""
&[[]] # Start of a numeric entity reference
(
[0-9]+[^0-9] # Decimal form
| 0[0-7]+[^0-7] # Octal form
| x[0-9a-fA-F]+[^0-9a-fA-F] # Hexadecimal form
)
""", re.VERBOSE)
没有 verbose 设置, RE 会看起来象这样:
#!python
charref = re.compile("([0-9]+[^0-9]"
"|0[0-7]+[^0-7]"
"|x[0-9a-fA-F]+[^0-9a-fA-F])")在上面的例子里,Python 的字符串自动连接可以用来将 RE 分成更小的部分,但它比用 re.VERBOSE 标志时更难懂。
到目前为止,我们只展示了正则表达式的一部分功能。在本节,我们将展示一些新的元字符和如何使用组来检索被匹配的文本部分。
还有一些我们还没展示的元字符,其中的大部分将在本节展示。
剩下来要讨论的一部分元字符是零宽界定符(zero-width assertions)。它们并不会使引擎在处理字符串时更快;相反,它们根本就没有对应任何字符,只是简单的成功或失败。举个例子, "b 是一个在单词边界定位当前位置的界定符(assertions),这个位置根本就不会被 "b 改变。这意味着零宽界定符(zero-width assertions)将永远不会被重复,因为如果它们在给定位置匹配一次,那么它们很明显可以被匹配无数次。
|
可选项,或者 "or" 操作符。如果 A 和 B 是正则表达式,A|B 将匹配任何匹配了 "A" 或 "B" 的字符串。| 的优先级非常低,是为了当你有多字符串要选择时能适当地运行。Crow|Servo 将匹配"Crow" 或 "Servo", 而不是 "Cro", 一个 "w" 或 一个 "S", 和 "ervo"。
为了匹配字母 "|",可以用 "|,或将其包含在字符类中,如[|]。
^
匹配行首。除非设置 MULTILINE 标志,它只是匹配字符串的开始。在 MULTILINE 模式里,它也可以直接匹配字符串中的每个换行。
例如,如果你只希望匹配在行首单词 "From",那幺 RE 将用 ^From。
#!python
>>> print re.search('^From', 'From Here to Eternity')
<re.MatchObject instance at 80c1520>
>>> print re.search('^From', 'Reciting From Memory')
None$
匹配行尾,行尾被定义为要么是字符串尾,要么是一个换行字符後面的任何位置。
#!python
>>> print re.search('}$', '{block}')
<re.MatchObject instance at 80adfa8>
>>> print re.search('}$', '{block} ')
None
>>> print re.search('}$', '{block}"n')
<re.MatchObject instance at 80adfa8>匹配一个 "$",使用 "$ 或将其包含在字符类中,如[$]。
"A
只匹配字符串首。当不在 MULTILINE 模式,"A 和 ^ 实际上是一样的。然而,在 MULTILINE 模式里它们是不同的;"A 只是匹配字符串首,而 ^ 还可以匹配在换行符之後字符串的任何位置。
"Z
Matches only at the end of the string.
只匹配字符串尾。
"b
单词边界。这是个零宽界定符(zero-width assertions)只用以匹配单词的词首和词尾。单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标示的。
下面的例子只匹配 "class" 整个单词;而当它被包含在其他单词中时不匹配。
#!python
>>> p = re.compile(r'"bclass"b')
>>> print p.search('no class at all')
<re.MatchObject instance at 80c8f28>
>>> print p.search('the declassified algorithm')
None
>>> print p.search('one subclass is')
None当用这个特殊序列时你应该记住这里有两个微妙之处。第一个是 Python 字符串和正则表达式之间最糟的冲突。在 Python 字符串里,""b" 是反斜杠字符,ASCII值是8。如果你没有使用 raw 字符串时,那幺 Python 将会把 ""b" 转换成一个回退符,你的 RE 将无法象你希望的那样匹配它了。下面的例子看起来和我们前面的 RE 一样,但在 RE 字符串前少了一个 "r" 。
#!python
>>> p = re.compile('"bclass"b')
>>> print p.search('no class at all')
None
>>> print p.search('"b' + 'class' + '"b')
<re.MatchObject instance at 80c3ee0>第二个在字符类中,这个限定符(assertion)不起作用,"b 表示回退符,以便与 Python 字符串兼容。
"B
另一个零宽界定符(zero-width assertions),它正好同 "b 相反,只在当前位置不在单词边界时匹配。
你经常需要得到比 RE 是否匹配还要多的信息。正则表达式常常用来分析字符串,编写一个 RE 匹配感兴趣的部分并将其分成几个小组。举个例子,一个 RFC-822 的头部用 ":" 隔成一个头部名和一个值,这就可以通过编写一个正则表达式匹配整个头部,用一组匹配头部名,另一组匹配头部值的方式来处理。
组是通过 "(" 和 ")" 元字符来标识的。 "(" 和 ")" 有很多在数学表达式中相同的意思;它们一起把在它们里面的表达式组成一组。举个例子,你可以用重复限制符,象 *, +, ?, 和 {m,n},来重复组里的内容,比如说(ab)* 将匹配零或更多个重复的 "ab"。
组用 "(" 和 ")" 来指定,并且得到它们匹配文本的开始和结尾索引;这就可以通过一个参数用 group()、start()、end() 和 span() 来进行检索。组是从 0 开始计数的。组 0 总是存在;它就是整个 RE,所以 `MatchObject` 的方法都把组 0 作为它们缺省的参数。稍後我们将看到怎样表达不能得到它们所匹配文本的 span。
小组是从左向右计数的,从1开始。组可以被嵌套。计数的数值可以能过从左到右计算打开的括号数来确定。
#!python
>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
文章评论
共有 位脚本之家网友发表了评论我来说两句