Python正则表达式之零宽断言(4)
文章目錄
- 聲明
- |
- ^
- $
- \A
- \Z
- \b
- \B
- 分組
- 反向引用
- 注意
聲明
有些元字符它們不匹配任何字符,只是簡(jiǎn)單地表示成功或失敗,因此這些字符也稱(chēng)之為零寬斷言。例如 \b 表示當(dāng)前位置位于一個(gè)單詞的邊界,但 \b 并不能改變位置。因此,零寬斷言不應(yīng)該被重復(fù)使用,因?yàn)?\b 并不會(huì)修改當(dāng)前位置,所以 \b\b 跟 \b 是沒(méi)什么兩樣的。
解釋:
很多人可能不理解“改變位置”和“零寬斷言”的意思?我嘗試解釋下,比如 abc 匹配完 a 之后,咱的當(dāng)前位置就會(huì)移動(dòng),才能繼續(xù)匹配 b,依次類(lèi)推…但是 \babc 的話,\b 表示當(dāng)前位置在單詞的邊界(單詞的第一個(gè)字母或者最后一個(gè)字母),這時(shí)候當(dāng)前位置不會(huì)發(fā)生改變,接著將 a 與當(dāng)前位置的字符進(jìn)行匹配…
|
或操作符,對(duì)兩個(gè)正則表達(dá)式進(jìn)行或操作。如果 A 和 B 是正則表達(dá)式,A | B 會(huì)匹配 A 或 B 中出現(xiàn)的任何字符。為了能夠更加合理的工作,| 的優(yōu)先級(jí)非常低。例如 Fish|C 應(yīng)該匹配 Fish 或 C,而不是匹配 Fis,然后一個(gè) 'h' 或 'C'。
同樣,我們使用 \| 來(lái)匹配 '|' 字符本身;或者包含在一個(gè)字符類(lèi)中,像這樣 [|]。
^
匹配字符串的起始位置。如果設(shè)置了 MULTILINE 標(biāo)志,就會(huì)變成匹配每一行的起始位置。在 MULTILINE 中,每當(dāng)遇到換行符就會(huì)立刻進(jìn)行匹配。
舉個(gè)例子,如果你只希望匹配位于字符串開(kāi)頭的單詞 From,那么你的正則表達(dá)式可以寫(xiě)為 ^From:
實(shí)現(xiàn)結(jié)果:
$
匹配字符串的結(jié)束位置,每當(dāng)遇到換行符也會(huì)離開(kāi)進(jìn)行匹配。
>>> print(re.search('}$', '{block}')) <_sre.SRE_Match object; span=(6, 7), match='}'> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) <_sre.SRE_Match object; span=(6, 7), match='}'>實(shí)現(xiàn)結(jié)果:
同樣,我們使用 \$ 來(lái)匹配 '$' 字符本身;或者包含在一個(gè)字符類(lèi)中,像這樣 [$]。
print(re.search('}[$]', '{block}$')) print(re.search('}\$', '{block}$'))實(shí)現(xiàn)結(jié)果:
\A
只匹配字符串的起始位置。如果沒(méi)有設(shè)置 MULTILINE 標(biāo)志的時(shí)候,\A 和 ^ 的功能是一樣的;但如果設(shè)置了 MULTILINE 標(biāo)志,則會(huì)有一些不同:\A 還是匹配字符串的起始位置,但 ^ 會(huì)對(duì)字符串中的每一行都進(jìn)行匹配
\Z
只匹配字符串的結(jié)束位置。
\b
單詞邊界,這是一個(gè)只匹配單詞的開(kāi)始和結(jié)尾的零寬斷言。“單詞”定義為一個(gè)字母數(shù)字的序列,所以單詞的結(jié)束指的是空格或者非字母數(shù)字的字符。
下邊例子中,class 只有在出現(xiàn)一個(gè)完整的單詞 class 時(shí)才匹配;如果出現(xiàn)在別的單詞中,并不會(huì)匹配。
>>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) <_sre.SRE_Match object; span=(3, 8), match='class'> >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) None實(shí)現(xiàn)結(jié)果:
在使用這些特殊的序列的時(shí)候,有兩點(diǎn)是需要注意的:第一點(diǎn)需要注意的是,Python 的字符串跟正則表達(dá)式在有些字符上是有沖突的(回憶之前反斜杠的例子)。比如說(shuō)在 Python 中,\b 表示的是退格符(ASCII 碼值是 8)。所以,你如果不使用原始字符串,Python 會(huì)將 \b 轉(zhuǎn)換成退格符處理,這樣就肯定跟你的預(yù)期不一樣了。
下邊的例子中,我們故意不寫(xiě)表示原始字符串的 'r',結(jié)果確實(shí)大相庭徑:
>>> p = re.compile('\bclass\b') >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b')) <_sre.SRE_Match object; span=(0, 7), match='\x08class\x08'>實(shí)現(xiàn)結(jié)果:
第二點(diǎn)需要注意的是,在字符類(lèi)中不能使用這個(gè)斷言。跟 Python 一樣,在字符類(lèi)中,\b 只是用來(lái)表示退格符。
\B
一個(gè)零寬斷言,與 \b 的含義相反,\B 表示非單詞邊界的位置。
分組
通常在實(shí)際的應(yīng)用過(guò)程中,我們除了需要知道一個(gè)正則表達(dá)式是否匹配之外,還需要更多的信息。對(duì)于比較復(fù)雜的內(nèi)容,正則表達(dá)式通常使用分組的方式分別對(duì)不同內(nèi)容進(jìn)行匹配。
下邊的例子,我們將 RFC-822 頭用“:”號(hào)分成名字和值分別匹配:
From: author@example.com User-Agent: Thunderbird 1.5.0.9 (X11/20061227) MIME-Version: 1.0 To: editor@example.com像這種情況,我們就可以寫(xiě)一個(gè)正則表達(dá)式先來(lái)匹配一整個(gè) RFC-822 頭,然后利用分組功能,使用一個(gè)組來(lái)匹配頭的名字,另一個(gè)組匹配名字對(duì)應(yīng)的值。
RFC-822 是電子郵件的標(biāo)準(zhǔn)格式,當(dāng)然看到這里你還不知道分組要怎么分,不急,請(qǐng)接著往下看…
在正則表達(dá)式中,使用元字符 ( ) 來(lái)劃分組。( ) 元字符跟數(shù)學(xué)表達(dá)式中的小括號(hào)含義差不多;它們將包含在內(nèi)部的表達(dá)式組合在一起,所以你可以對(duì)一個(gè)組的內(nèi)容使用重復(fù)操作的元字符,例如 *,+,? 或者 {m,n}。
例如,(ab)* 會(huì)匹配零個(gè)或者多個(gè) ab:
>>> p = re.compile('(ab)*') >>> print(p.match('ababababab').span()) (0, 10)
使用 ( ) 表示的子組我們還可以對(duì)它進(jìn)行按層次索引,可以將索引值作為參數(shù)傳遞給這些方法:group(),start(),end() 和 span()。序號(hào) 0 表示第一個(gè)分組(這個(gè)是默認(rèn)分組,一直存在的,所以不傳入?yún)?shù)相當(dāng)于默認(rèn)值 0):
>>> p = re.compile('(a)b') >>> m = p.match('ab') >>> m.group() 'ab' >>> m.group(0) 'ab'有幾對(duì)小括號(hào)就是分成了幾個(gè)子組,例如 (a)(b) 和 (a(b)) 都是由兩個(gè)子組構(gòu)成的。
子組的索引值是從左到右進(jìn)行編號(hào),子組也允許嵌套,因此我們可以通過(guò)從左往右來(lái)統(tǒng)計(jì)左括號(hào) ( 來(lái)確定子組的序號(hào)。
>>> p = re.compile('(a(b)c)d') >>> m = p.match('abcd') >>> m.group(0) 'abcd' >>> m.group(1) 'abc' >>> m.group(2) 'b'group() 方法可以一次傳入多個(gè)子組的序號(hào):
>>> m.group(2,1,2) ('b', 'abc', 'b')start() 是獲得參數(shù)子組的開(kāi)始位置;end() 是獲得對(duì)應(yīng)子組的結(jié)束位置;span() 是獲得對(duì)應(yīng)子組的范圍。
可以通過(guò) groups() 方法一次性返回所有的子組匹配的字符串:
>>> m.groups() ('abc', 'b')反向引用
還有一個(gè)反向引用的概念需要介紹。反向引用指的是你可以在后面的位置使用先前匹配過(guò)的內(nèi)容,用法是反斜杠加上數(shù)字。例如 \1 表示引用前邊成功匹配的序號(hào)為 1 的子組。
>>> p = re.compile(r'(\b\w+)\s+\1') >>> p.search('Paris in the the spring').group() 'the the'如果只是搜索字符串,反向引用不會(huì)被用到,因?yàn)?strong>很少有文本格式會(huì)這樣來(lái)重復(fù)字符。但是,你很快會(huì)發(fā)現(xiàn),在字符串替換的時(shí)候,反向引用是非常有用的!
注意
在 Python 的字符串中會(huì)使用反斜杠加數(shù)字的方式來(lái)表示數(shù)字的值對(duì)應(yīng)的 ASCII 字符,所以在使用反向索引的正則表達(dá)式中,我們依然強(qiáng)調(diào)要使用原始字符串。
總結(jié)
以上是生活随笔為你收集整理的Python正则表达式之零宽断言(4)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Python通过代理ip访问网站
- 下一篇: Web前端三剑客之HTML基础