Python 正則表達式 Howto(6)

更強大的功能

到目前爲止,我們只是瞭解了一部分正則表達式的功能,在本章節我們會看一些特殊的匹配字符,以及使用組功能來取得串的匹配位置。

更多匹配字符

在以前的章節中,我們並沒有覆蓋所有的匹配字符,本章中我們覆蓋他們中的大部分。

他們中有些部分是所謂的零寬斷言,也就是說他們不會匹配任何字符,只是簡單的表示成功或者失敗。比如\b 表示現在的位置在單詞邊界上,位置不會被\b 改變。也就是說零寬斷言永遠不應該被重複,因爲位置匹配一旦被匹配上幾次,既可以隨便匹配多少次。

|

表示兩個表格式的或操作。如果A和B是正則表達式, A|B 會匹配A 或 B 中出現的任何字符。爲了使其更加合理的工作, | 的優先級比較低. 比如,Crow|Servo 會匹配 Crow 或者Servo, 而不是 Cro, 一個 'w' 或者 一個 'S', 和 ervo.

同理爲了匹配字面的 '|', 我們應該使用 \|, 或者用中括號括起來使之形成一個字符集,像這樣寫 [|].

^

匹配字符串中的起始部分,除非設置了MULTILINE  標誌。一旦設置了這個標誌,就只會匹配每一行起始部分而不是字符串的其實部分。在MULTILINE  中,每每遇到換行就會立刻匹配。

舉例來說,如果你只是想在字符串的起始部分匹配From ,正則表達式應該寫成 ^From.

>>> 

>>> print re.search('^From','From Here to Eternity')  
<_sre.SRE_Match object at 0x...>
>>> print re.search('^From','Reciting From Memory')
None

$

匹配一行的最末位置。會匹配一個字符串的末尾,或者是一行的行尾。

>>> 

>>> print re.search('}$','{block}')  
<_sre.SRE_Match object at 0x...>
>>> print re.search('}$','{block} ')
None
>>> print re.search('}$','{block}\n')  
<_sre.SRE_Match object at 0x...>

爲了匹配字面上的'$', 同樣應該使用 \$ 或者使用中括號包裹,寫成 [$].

\A

只會匹配字符串的其實位置,如果沒有設置了MULTILINE  標誌, \A 和 ^ 功能上基本一樣。. 在 MULTILINE 模式下, 有一些不同: \A 仍然不改變其原有含義,只是匹配字符串的起始位置, 但是 ^ 會針對於每一行都會有一次匹配。

\Z

只是匹配字符串的結束位置,不受MULTILINE 標誌影響.

\b

單詞界. 這是一個只是匹配單詞的開始以及結尾的零寬斷言. 單詞的含義是指一個字符數字的序列,所以單詞的結束指的是空格或者是非字母數字。

下面的例子中 class 只有在出現一個完整的單詞class時纔會匹配; 如果其出現在別的單詞中,不會匹配。

>>> 

>>> p= re.compile(r'\bclass\b')
>>> print p.search('no class at all')  
<_sre.SRE_Match object at 0x...>
>>> print p.search('the declassified algorithm')
None                  
>>> print p.search('one subclass is')
None

在使用這些特殊的序列的時候,有兩點需要注意:第一個是要注意Python本身的內置字符可能跟這些字符是有衝突的。比如說在Python中,\b 表示回退字符。其ASCII的值是8.如果你不使用原生串,Python會將\b轉換成回退字符(8),這樣的話跟你的 預期肯定是不一樣的。下面的例子中看上去跟前面的正則表達式一樣,只是少了’r’, 但是結果卻大相徑庭:

>>> 

>>> p= re.compile('\bclass\b')
>>> print p.search('no class at all')
None
>>> print p.search('\b'+'class'+'\b')  
<_sre.SRE_Match object at 0x...>

第二點需要注意的是,在字符集中不能使用此斷言,跟python一樣,\b只是用來標示回退字符。

\B

       跟\b 相反, 只是用來標示非單詞界。

劃分組

在實際使用過程中,除了知道一個RE是否匹配之外,我們需要更多的信息。正則表達式通常會通過一種將RE劃分成若干子串來匹配感興趣的部分的形式來剖析子串。例如,一個RFC-822的頭部被分成頭名字,值,中間使用一個':'分開, 如下:

From: [email protected]
User-Agent: Thunderbird 1.5.0.9 (X11/20061227)
MIME-Version: 1.0
To: [email protected]

像這樣的情況,我們可是使用正則表達式來匹配一整個頭,然後使用一個組來匹配頭的名字,另外一個組匹配頭部的值。

在正則表達式中,組使用'(', ')' 特殊字符來劃分。 '(' 和 ')' 跟數學表達式中小括號的意思差不多; 他們將內部的表達式組合在一起,所以你可以使用就像 *, +, ?, 或者 {m,n}重複操作碼來重複其內容,比如, (ab)* 會匹配零個或者是多個 ab.

>>> 

>>> p= re.compile('(ab)*')
>>> print p.match('ababababab').span()
(0, 10)

使用 '(', ')'包裹起來的組也可以捕捉這些組在匹配文本的起始以及結束的位置。這些值可以通過向group(),start()end(), and span()中傳入參數來完成。在匹配對象中將參數0作爲默認參數。

>>> 

>>> p= re.compile('(a)b')
>>> m= p.match('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'

子組是從1開始從左到右計數,組同時也可以嵌套,我們可以通過從左往右統計左括號來確定組的index.

>>> 

>>> p= re.compile('(a(b)c)d')
>>> m= p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'

group() 可以一次性傳入多個組的index, 這種情況下,其將會返回包含相應值得元組:

>>> 

>>> m.group(2,1,2)
('b', 'abc', 'b')

groups() 方法返回包含所有子組匹配值的元組:

>>> 

>>> m.groups()
('abc', 'b')

匹配模式中反向引用是指你可以在後面的模式中使用先前匹配的串,前提條件是這個匹配必須成功。比如, \1 會匹配成功如果組1的內容在前面被精準匹配,否則就會失敗。請記住,Python語言中同樣會使用反斜槓加數字的方式來表示其ASCII值等於那個數字的字符,所以在使用反向引用的正則表達式中我們最好使用原生串。

舉個例子,下面的正則表達式重複的單詞:

>>> 

>>> p= re.compile(r'(\b\w+)\s+\1')
>>> p.search('Paris in the the spring').group()
'the the'

如果只是爲了搜索某個字符串,反向引用不會被經常使用。很少有文本格式會這樣來重複字符。但是, 你會很快就會發現其在字符替換的時候非常有用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章