无捕获组和命名组

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

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

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

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

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

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

#!python
>>> m = re.match("([abc])+", "abc")
>>> m.groups()
('c',)
>>> m = re.match("(?:[abc])+", "abc")
>>> m.groups()
()

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

其次,更重要和强大的是命名组;与用数字指定组不一样的是,它能够用名字来指定。io

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

#!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'