文章目錄
Regex的使用
學習過最簡單的Regex的規則後,如何在實際中運用呢?Python中的re模組提供了Regex引擎的介面,允許使用者將運算式編譯成對象,然後再進行匹配。
Regex的編譯
將Regex編譯成格式對象,此對象含有不同的操作函數,如尋找或子串替換等。
>>> import re
>>> p = re.compile('ab*')
>>> print p
<_sre.SRE_Pattern object at 0x...>
Re.compile()也可以接受一個可選的參數flag,來選擇不同的特殊功能和文法變體。我們先運行一個例子,再來講解flag的設定:
>>> p = re.compile('ab*', re.IGNORECASE)
將Regex樣式作為一個字串傳遞給re.compile(),這是由於Regex不是Python的核心功能,所以也沒有它的特殊文法(有些程式根本用不到Regex的功能,因而沒有必要將它放進核心文法中),但是re模組作為C語言的擴充被包含到Python的模組中,類似的還有socket或zlib模組。
將Regex樣式設計為字串可以使Python語言更加簡單,但是它有一個缺點,將在下一節講解。
反斜線\問題
如前所述,Regex使用反斜線來表明特殊形式或取消特殊意義,而Python在字串中同樣使用反斜線來實現相同意圖,從而帶來了衝突。
比如說你想寫出一個Regex樣式來匹配LaTeX中的\section,首先必須寫出相應的樣式,然後必須在每一個反斜線前再加一個反斜線來,如\\section,這個結果將傳遞給re.compile。然而,為了表示這是一個Python的字串,每一個反斜線必須再加一個反斜線!
字元 |
狀態 |
\section |
想要匹配的字元 |
\\section |
為re.compile()去掉反斜線 |
“\\\\section” |
再加一個反斜線來表明它是一個字串而非有特殊意義的單詞 |
簡而言之,對了匹配一個無任何特殊意義的反斜線,必須為Regex樣式寫上\\\\,因為Regex必須為\\,而Python字串中的每一個無特殊含義的反斜線都必須以\\來代替。在Regex中,使用反斜線的情況常常碰見,這將導致無數多數的反覆輸入反斜線,從而造成最終的字串難於理解。
解決方案是使用Python的未轉義的字串聲明:在以r為首碼的字串中,反斜線解除特殊含義,如r"\n"是一個包含兩個字元的字串,而"\n"則是一個字元表示換行。所以在Python代碼中要使用這種表示方法來書寫Regex。
Regex的樣式 |
對應的未經轉義的字串 |
“ab*” |
r”ab*” |
“\\\\section” |
r”\\section” |
“\\w+\\s+\\s” |
r”\w+\s+\1” |
匹配
當你有一個表示Regex的對象時,應當如何使用?樣式對象有不同的方法和屬性,這裡只列出了最為常用的幾個,包含全部方法和屬性的列表請參考re的協助文檔。
方法或屬性 |
用途 |
match() |
檢查是否在字串的開始處匹配 |
search() |
在字串中掃描並尋找匹配的位置 |
findall() |
尋找所有匹配的子串,並將結果返回到一個列表中 |
finditer() |
尋找所有匹配的子串,並將它們作為迭代器返回 |
如果沒有匹配成功,則match()和search()返回None;如果成功,將返回一個MatchObject對象,包含了匹配開始和結束的資訊、匹配的子串等等。
可以通過re模組來學習匹配的使用。如果你的系統安裝有Tkinter,也可以查看Tools/scripts/redemo.py,它是Python發行版中包含的一個示範程式,允許你輸入Regex和字串並進行匹配。該示範程式在進行調試複雜的Regex程式時非常有用。Phil Schwartz的Kodos也是一個用於Regex開發與測試的互動式工具。
本文檔使用Python標準的解譯器來完成執行個體。首先,開啟Python解譯器,匯入re模組,對Regex進行編譯:
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = re.compile('[a-z]+')
>>> p
<_sre.SRE_Pattern object at 0x...>
現在你可以針對Regex[a-z]+嘗試匹配不同的字串。一個空串肯定不會匹配,因為+表示匹配一個或多個,這種情況下調用match()應當返回None,這時Python解譯器不會有任何輸出,你可以通過顯式的列印出匹配的結果來查看。
>>> p.match("")
>>> print p.match("")
None
接著來嘗試一個可以匹配的字串,這裡match()將返回一個MatchObject,你可以將這個Object Storage Service在變數中以便以後使用。
>>> m = p.match('tempo')
>>> print m
<_sre.SRE_Match object at 0x...>
可以請求MatchObject來查看匹配資訊,它也包含不同的方法和屬性,最重要的有:
方法或屬性 |
用途 |
group() |
返回匹配的字串 |
start() |
返回匹配的開始位置(下標) |
end() |
返回匹配的結束位置 |
span() |
返回一個元組,它包含匹配的(開始,結束)的位置 |
嘗試以下方法將闡明上面這些方法的意思:
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)
由於match()只檢查字串的起始位置,start()一定為0,但search()方法將遍曆整個字串,所以匹配可能不在起始位置。
>>> print p.match('::: message')
None
>>> m = p.search('::: message') ; print m
<_sre.SRE_Match object at 0x...>
>>> m.group()
'message'
>>> m.span()
(4, 11)
在實際的程式中,最常用的做法是將MatchObject儲存在變數中,然後查檢是否為None,例如:
p = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'
兩個成員函數將返回所有的匹配,其中一個是findall(),它返回匹配字串的列表:
>>> p = re.compile('\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
['12', '11', '10']
findall()必須在返回結果前建立整個列表,finditer()函數返回MatchObject對象序列的迭代器:
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable-iterator object at 0x401833ac>
>>> for match in iterator:
... print match.span()
...
(0, 2)
(22, 24)
(29, 31)