您的位置:首页 > 编程语言 > Python开发

比较详细Python正则表达式操作指南(re使用)[7]

2014-04-19 23:10 696 查看

无捕获组和命名组

精心设计的 REs 也许会用很多组,既可以捕获感兴趣的子串,又可以分组和结构化 RE 本身。在复杂的 REs 里,追踪组号变得困难。有两个功能可以对这个问题有所帮助。它们也都使用正则表达式扩展的通用语法,因此我们来看看第一个。

Perl 5 对标准正则表达式增加了几个附加功能,Python
re 模块也支持其中的大部分。选择一个新的单按键元字符或一个以 """ 开始的特殊序列来表示新的功能,而又不会使 Perl 正则表达式与标准正则表达式产生混乱是有难度的。如果你选择
"&" 做为新的元字符,举个例子,老的表达式认为 "&" 是一个正常的字符,而不会在使用 "& 或 [&] 时也不会转义。

Perl 开发人员的解决方法是使用 (?...) 来做为扩展语法。"?" 在括号後面会直接导致一个语法错误,因为 "?" 没有任何字符可以重复,因此它不会产生任何兼容问题。紧随 "?" 之後的字符指出扩展的用途,因此 (?=foo)

Python 新增了一个扩展语法到 Perl 扩展语法中。如果在问号後的第一个字符是 "P",你就可以知道它是针对Python 的扩展。目前有两个这样的扩展:
(?P<name>...) 定义一个命名组,(?P=name) 则是对命名组的逆向引用。如果 Perl 5 的未来版本使用不同的语法增加了相同的功能,那幺 re 模块也将改变以支持新的语法,这是为了兼容性的目的而保持的 Python 专用语法。

现在我们看一下普通的扩展语法,我们回过头来简化在复杂 REs 中使用组运行的特性。因为组是从左到右编号的,而且一个复杂的表达式也许会使用许多组,它可以使跟踪当前组号变得困难,而修改如此复杂的 RE 是十分麻烦的。在开始时插入一个新组,你可以改变它之後的每个组号。

首先,有时你想用一个组去收集正则表达式的一部分,但又对组的内容不感兴趣。你可以用一个无捕获组: (?:...) 来实现这项功能,这样你可以在括号中发送任何其他正则表达式。


#!python




>>> m = re.match("([abc])+", "abc")




>>> m.groups()




('c',)




>>> m = re.match("(?:[abc])+", "abc")




>>> m.groups()




()

除了捕获匹配组的内容之外,无捕获组与捕获组表现完全一样;你可以在其中放置任何字符,可以用重复元字符如 "*" 来重复它,可以在其他组(无捕获组与捕获组)中嵌套它。(?:...) 对于修改已有组尤其有用,因为你可以不用改变所有其他组号的情况下添加一个新组。捕获组和无捕获组在搜索效率方面也没什么不同,没有哪一个比另一个更快。

其次,更重要和强大的是命名组;与用数字指定组不同的是,它可以用名字来指定。

命令组的语法是 Python 专用扩展之一: (?P<name>...)。名字很明显是组的名字。除了该组有个名字之外,命名组也同捕获组是相同的。`MatchObject` 的方法处理捕获组时接受的要么是表示组号的整数,要么是包含组名的字符串。命名组也可以是数字,所以你可以通过两种方式来得到一个组的信息:


#!python




>>> p = re.compile(r'(?P<word>"b"w+"b)')




>>> m = p.search( '((((
Lots of punctuation )))' )




>>> m.group('word')




'Lots'




>>> m.group(1)




'Lots'

命名组是便于使用的,因为它可以让你使用容易记住的名字来代替不得不记住的数字。这里有一个来自 imaplib 模块的 RE 示例:


#!python




InternalDate = re.compile(r'INTERNALDATE
"'




r'(?P<day>[
123][0-9])-(?P<mon>[A-Z][a-z][a-z])-'




r'(?P<year>[0-9][0-9][0-9][0-9])'




r' (?P<hour>[0-9][0-9]):(?P<min>[0-9][0-9]):(?P<sec>[0-9][0-9])'




r' (?P<zonen>[-+])(?P<zoneh>[0-9][0-9])(?P<zonem>[0-9][0-9])'




r'"')

很明显,得到 m.group('zonem') 要比记住得到组 9 要容易得多。

因为逆向引用的语法,象 (...)"1 这样的表达式所表示的是组号,这时用组名代替组号自然会有差别。还有一个 Python 扩展:(?P=name) ,它可以使叫 name 的组内容再次在当前位置发现。正则表达式为了找到重复的单词,("b"w+)"s+"1
也可以被写成 (?P<word>"b"w+)"s+(?P=word):


#!python




>>> p = re.compile(r'(?P<word>"b"w+)"s+(?P=word)')




>>> p.search('Paris
in the the spring').group()




'the
the'
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: