PYTHON正则表达式re模块使⽤说明
⾸先,运⾏ Python 解释器,导⼊ re 模块并编译⼀个 RE:
#!python
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = repile('[a-z]+')
>>> p
<_sre.SRE_Pattern object at 80c3c28>
现在,你可以试着⽤ RE 的 [a-z]+ 去匹配不同的字符串。⼀个空字符串将根本不能匹配,因为 + 的意思是 “⼀个或更多的重复次数”。在这种情况下 match() 将返回 None,因为它使解释器没有输出。你可以明确地打印出 match() 的结果来弄清这⼀点。
#!python
>>> p.match("")
>>> print p.match("")
None
现在,让我们试着⽤它来匹配⼀个字符串,如 "tempo"。这时,match() 将返回⼀个 MatchObject。因此你可以将结果保存在变量⾥以便后⾯使⽤。
#!python
>>> m = p.match( 'tempo')
>>> print m
<_sre.SRE_Match object at 80c4f68>
现在你可以查询 `MatchObject` 关于匹配字符串的相关信息了。MatchObject 实例也有⼏个⽅法和属性;最重要的那些如下所⽰:
⽅法/属性作⽤
group()返回被 RE 匹配的字符串
start()返回匹配开始的位置
end()返回匹配结束的位置
span()返回⼀个元组包含匹配 (开始,结束) 的位置
试试这些⽅法不久就会清楚它们的作⽤了:
#!python
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)
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 = repile( ... )
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'
两个 `RegexObject` ⽅法返回所有匹配模式的⼦串。findall()返回⼀个匹配字符串⾏表:
#!python
>>> p = repile('\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 = repile( ... )
entityref = repile( ... )
charref = repile( ... )
starttagopen = repile( ... )
我通常更喜欢使⽤编译对象,甚⾄它只⽤⼀次,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 状态,使之被组织得更清晰易懂
python正则表达式不包含使匹配对⼤⼩写不敏感;字符类和字符串匹配字母时忽略⼤⼩写。举个例⼦,[A-Z]也可以匹配⼩写字母,Spam 可以匹配"Spam", "spam", 或 "spAM"。这个⼩写字母并不考虑当前位置。
影响 \w, \W, \b, 和 \B,这取决于当前的本地化设置。
locales 是 C 语⾔库中的⼀项功能,是⽤来为需要考虑不同语⾔的编程提供帮助的。举个例⼦,如果你正在处理法⽂⽂本,你想⽤ \w+ 来匹配⽂字,但 \w 只匹配字符类 [A-Za-z];它并不能匹配 "é" 或 "ç"。如果你的系统配置适当且本地化设置为法语,那么内部的 C 函数将告诉程序 "é" 也应该被认为是⼀个字母。当在编译正则表达式时使⽤ LOCALE 标志会得到⽤这些 C 函数来处理 \w 后的编译对象;这会更慢,但也会象你希望的那样可以⽤ \w+ 来匹配法⽂⽂本。
(此时 ^ 和 $ 不会被解释; 它们将在 4.1 节被介绍.)
使⽤ "^" 只匹配字符串的开始,⽽ $ 则只匹配字符串的结尾和直接在换⾏前(如果有的话)的字符串结尾。当本标志指定后,"^" 匹配字符串的开始和字符串中每⾏的开始。同样的, $ 元字符匹配字符串结尾和字符串中每⾏的结尾(直接在每个换⾏之前)。
使 "." 特殊字符完全匹配任何字符,包括换⾏;没有这个标志, "." 匹配除了换⾏外的任何字符。
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。当该标志被指定时,在 RE 字符串中的空⽩符被忽略,除⾮该空⽩符在字符类中或在反斜杠之后;这可以让你更清晰地组织和缩进 RE。它也可以允许你将注释写⼊ RE,这些注释会被引擎忽略;注释⽤ "#"号来标识,不过该符号不能在字符串或反斜杠之后。
举个例⼦,这⾥有⼀个使⽤ re.VERBOSE 的 RE;看看读它轻松了多少?
#!python
charref = repile(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 = repile("&#([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>
匹配⼀个 "$",使⽤ \$ 或将其包含在字符类中,如[$]。
只匹配字符串⾸。当不在 MULTILINE 模式,\A 和 ^ 实际上是⼀样的。然⽽,在 MULTILINE 模式⾥它们是不同的;\A 只是匹配字符串⾸,⽽ ^ 还可以匹配在换⾏符之后字符串的任何位置。
Matches only at the end of the string.
只匹配字符串尾。
单词边界。这是个零宽界定符(zero-width assertions)只⽤以匹配单词的词⾸和词尾。单词被定义为⼀个字母数字序列,因此词尾就是⽤空⽩符或⾮字母数字符来标⽰的。
下⾯的例⼦只匹配 "class" 整个单词;⽽当它被包含在其他单词中时不匹配。
#!python
>>> p = repile(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 = repile('\bclass\b')
>>> print p.search('no class at all')
None
>>> print p.search('\b' + 'class' + '\b')
<re.MatchObject instance at 80c3ee0>
第⼆个在字符类中,这个限定符(assertion)不起作⽤,\b 表⽰回退符,以便与 Python 字符串兼容。
另⼀个零宽界定符(zero-width assertions),它正好同 \b 相反,只在当前位置不在单词边界时匹配。
分组
你经常需要得到⽐ RE 是否匹配还要多的信息。正则表达式常常⽤来分析字符串,编写⼀个 RE 匹配感兴趣的部分并将其分成⼏个⼩组。举个例⼦,⼀个 RFC-822 的头部⽤ ":" 隔成⼀个头部名和⼀个值,这就可以通过编写⼀个正则表达式匹配整个头部,⽤⼀组匹配头部名,另⼀组匹配头部值的⽅式来处理。
组是通过 "(" 和 ")" 元字符来标识的。 "(" 和 ")" 有很多在数学表达式中相同的意思;它们⼀起把在它们
⾥⾯的表达式组成⼀组。举个例⼦,你可以⽤重复限制符,象 *, +, ?, 和 {m,n},来重复组⾥的内容,⽐如说(ab)* 将匹配零或更多个重复的 "ab"。
#!python
>>> p = repile('(ab)*')
>>> print p.match('ababababab').span()
(0, 10)
组⽤ "(" 和 ")" 来指定,并且得到它们匹配⽂本的开始和结尾索引;这就可以通过⼀个参数⽤ group()、start()、end() 和 span()来进⾏检索。组是从 0 开始计数的。组 0 总是存在;它就是整个 RE,所以 `MatchObject` 的⽅法都把组 0 作为它们缺省的参数。稍后我们将看到怎样表达不能得到它们所匹配⽂本的 span。
#!python
>>> p = repile('(a)b')
>>> m = p.match('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'
⼩组是从左向右计数的,从1开始。组可以被嵌套。计数的数值可以能过从左到右计算打开的括号数来确定。
#!python
>>> p = repile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
group() 可以⼀次输⼊多个组号,在这种情况下它将返回⼀个包含那些组所对应值的元组。
#!python
>>> m.group(2,1,2)
('b', 'abc', 'b')
The groups() ⽅法返回⼀个包含所有⼩组字符串的元组,从 1 到所含的⼩组号。
#!python
>>> m.groups()
('abc', 'b')
模式中的逆向引⽤允许你指定先前捕获组的内容,该组也必须在字符串当前位置被到。举个例⼦,如果组 1 的内容能够在

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。