無捕獲組和命名組

精心設計的 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'
相關文章
相關標籤/搜索