1. 程式人生 > >python re正則表示式說明文件

python re正則表示式說明文件

這個文件是一個關於用Python中的re模組來使用正則表示式的教程。

1、序言

re 模組在Python1.5中被加入,並且提供了Perl型別的正則表示式模式。較早的Python版本用的是regex模組,它提供Emacs型別模式。 Emacs型別模式可讀性差並且沒有提供很多特性,因此當我們寫新的程式碼的時候沒有必要去使用regex模組,儘管你可能會碰到一些使用了它的老程式碼。

正 則表示式本質上是一個很小的且高度專用的程式語言,它嵌入在Python中且通過re模組可用。在使用這個小的語言的時候,你要為你想要匹配的可能的字元 串指定規則;要匹配的字串可以是英語句子,或e-mail地址,或TeX命令,或你喜歡的任何東西。你可問問題如“這個字串匹配這個模式嗎?”,呀“ 在這個字串中有與這個模式匹配的嗎?”。你可以使用正則表示式去修改一個字串或用不同的方法分離它。

正則表示式模式被編譯成連續的字 節碼,這些位元組碼然後被用C寫成的匹配引擎執行。關於高階的使用,必須要仔細關心這個引擎如何去執行一個給定的正則表示式和你寫怎樣的正則表示式它所產生 的位元組碼執行的更快。這篇文件不涉及優化,因為它要求你對匹配引擎的內部組織有一個好的理解。

正則表示式語言是一個相對小而有限,因此不 是所有的字串處理任務都可以用正則表示式來完成。這其中雖然有一些任務可以用正則表示式來完成,但這個表示式是非常複雜的。這種情況下,更好的方法是寫 Python程式碼來處理,儘管Python程式碼比精巧的正則表示式執行的慢,但它更易理解。

2、簡單模式

我們將以學習最簡單的正則表示式作為開始。因為正則表示式用於處理字串,所以我們將以最通常的任務:匹配字元 作為開始。

2.1、匹配字元

大部分的字母和字元都將只匹配它們自身。例如正則表示式test將正確地匹配字串“test”(你也可以使用大寫不敏感模式使之匹配”Test”或”TEST”)。

大部分的字母和字元都將只匹配它們自身,這個規則也有例外;有些字元是專用的,不與自身匹配。相反,它們表示本身意義之外的東西將被匹配,或者通過重複它們來影響正則表示式的其它部分。這個文件的大部分是專門討論各種元字元和它們的作用。

下面是元字元的完整列表;它們的意義將在文件的其餘部分討論。
. ^ $ * + ? { [ ] \ | ( )
我們首先關注的元字元是”[“和”]”。 它們被用來指定一類字元,是一套你想去匹配的字元。字元可以分別列出,或使用兩個字元中間用”-“分離來表示一定範圍的字元。例如,[abc]將匹 配”a”,”b”,或”c”中的任一個;這與[a-c]是一樣的作用,[a-c]指定了要匹配的字元範圍。如果你只想匹配小寫字母,你的正則表示式應是 [a-z]。

元字元在類別中是不活動的。例如,[akm]"a","k","m","”中的任一個,”$”通常是一個元字元,但是在字元類別中它脫離它的特殊性。

通過補充設定,你可以匹配不在一個範圍內的字元。這可通過在字元類別中包括一個”^”作為首字元;例如,[^5]將匹配除了”5”以外的任何字元。

也許最重要的元字元是反斜槓”\”。如同Python字面上的字串,反斜槓後可跟不同的字元去表示不同的特殊序列。它也被用來避免所有的元字元以便你仍然可以按模式匹配它們;例如,如果你需要匹配”[“或”\”,你可以在它們的前面加上一個反斜槓以消除它們特別的意思:[或\。

一些以”\”開始的特殊序列代表預定義一套字元,它們通常是有用的,諸如一套數字,一套字母或一套任何東西(不是空白)。下面的預定義的特殊序列是有效的:

\d 匹配任何十進位制的數字,等同於[0-9]
\D 匹配任何非數字字元,等同於[^0-9]
\s 匹配任何空白字元,等同於[ \t\n\r\f\v]
\S 匹配任何非空白字元,等同於[^ \t\n\r\f\v]
\w 匹配任何字母數字字元,等同於[a-zA-Z0-9_]
\W 匹配任何非字母數字字元,等同於[^a-zA-Z0-9_]

這些序列可以被包括在一個字元類別中。例如, [\s,.]是一個字元類別,它將匹配任何空白字元,或”,”或”.”。

最後討論的元字元是.。它匹配除了換行符的任何東西,這有一個候補的方法(re.DOTALL)匹配換行符。”.”經常用於在你想匹配任何字元時。

2.2、重複

我們要關注的這第一個用於重複的元字元是不能匹配字面意義上的”*”;相反,它指定前面的字元能夠被匹配0次或更多次。
例如,ca*t將匹配”ct”(0個”a”字元),”cat”(1個”a”),”caaat”(3個”a”字元)等等。

另一個重複操作的元字元是+,它匹配一次或多次。+要求其前的字元至少要出現一次。例如,ca+t將匹配”cat”(1個”a”),”caaat”(3個”a”),但是不匹配”ct”。

下面是?,它表示匹配一次或0次。例如,home-?brew將匹配”homebrew”或”home-brew”。

最複雜的是{m,n} ,m和n是十進位制整數。它們代表最少重複m次,並且最多重複n次。例如,a/{1,3}b將匹配”a/b”,”a//b”,和”a///b”。它不匹配”ab”,因為沒有斜槓,也不匹配”a////b”,因為有個斜槓。
你可以省略m或n,省略m將被認為最小為0,省略n將意味上限無窮大。

3、使用正則表示式

現在我們已經瞭解一些簡單的正則表示式,我們在Python中如何使用它們呢?re模組提供了一個正則表示式引擎的介面,讓你把正則表示式編譯成物件然後用它們執行匹配。

3.1、編譯正則表示式

正則表示式被編譯成RegexObject例項,它有關於各種操作的方法,如為匹配模式搜尋或執行字串替換。

import re
p = re.compile(‘ab*’)
print p

re.compile()也接受一個可選的標誌引數,用來使各種特別的特性和語法變種起作用。下面是一個簡單的例子:

p = re.compile(‘ab*’, re.IGNORECASE)
正則表示式被作為一個字串傳遞給re.compile()。正則表示式被作為字串處理是因為它不是核心Python語言的一部分,並且沒有為表示它們而建立專門的語法。相反,re模組僅是一個被Python所包括的C擴充套件模組,就象socket或zlib模組。

3.2、反斜槓的麻煩

如 前所述,正則表示式使用反斜槓來標識特殊的形式或允許特別的字元被使用而避開它們的特殊意義。但這在Python中是很麻煩的。例如你想寫一個正則表示式 去匹配字串”\section’,那麼正則表示式應是”\section”。然而在Python中,這個表示式要作為字面意義上的字串傳遞給 re.compile(),則應寫成”\\section”。這樣很難理解,解決的辦法是使用r字首,如r”\section”來表示字面意義上的 字串。

3.3、執行匹配

一旦你有了一個代表已編譯的正則表示式的物件時,你用它來做什麼呢?正則表示式物件例項有一些方法和屬性。下面是其中最重要的:

match() 確定正則表示式是否匹配字串的開頭
search() 掃描字串以查詢匹配
findall() 找到所有正則表示式匹配的子字串,並把它們作為一個列表返回
finditer() 找到所有正則表示式匹配的子字串,並把它們以指示器的形式返回

match()和search()在沒有發現匹配時返回None。如果匹配成功,一個MatchObject例項被返回,其中包含的匹配資訊有:哪開始哪結束,匹配的子字串等等。

你 可以通過互動式的試驗使用re模組來學習這個。如果你有一個有效的Tkinter,你可能想關注Tools/scripts/redemo.py,這是一 個包含在Python發行版中的演示程式。它允許你輸入正則表示式和字串,並且顯示正則表示式是否匹配。redemo.py在試圖除錯一個複雜的正則表 達式時可能是十分有用的。我們的文件將使用標準的Python直譯器來學習正則表示式。

首先執行Python直譯器,引入re模組並用編譯正則表示式:
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)

import re
p = re.compile(‘[a-z]+’)
p
<_sre.SRE_Pattern object at 80c3c28>
現在,現在你可以試著用正則表示式[a-z]+去匹配不同的字串。空字串不能匹配,因為+意味著一個或多個重複,這種情況下match()將返回None,它將使直譯器什麼都不輸出。你也可以顯示的列印match()的結果來讓這個更清楚。
p.match(“”)
print p.match(“”)
None
現在,讓我們試著匹配一個字串,如”tempo”。這種情況下,match()將返回一個MatchObject,因此你可以儲存這個結果到一個變數中以備後用。
m = p.match( ‘tempo’)
print m
<_sre.SRE_Match object at 80c4f68>

現在,你可以查詢MatchObject以獲取關於匹配字串的資訊。MatchObject例項也有一些方法和屬性;最重要的幾個如下:

group() 返回通過正則表示式匹配到的字串
start() 返回成功匹配開始位置
end() 返回成功匹配結束位置
span() 返回包含成功匹配開始和結束位置的元組

試一下這些方法將很快清楚它們的意思:

m.group()
‘tempo’
m.start(), m.end()
(0, 5)
m.span()
(0, 5)

因為match方法只檢查正則表示式是否匹配字串的開頭,所以start()總是返回0值。但是,RegexObject例項的search方法要掃描整個字串,這種情況下,成功匹配的開頭位置不一定會是0值。

print p.match(‘::: message’)
None
m = p.search(‘::: message’) ; print m

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’

有兩個RegexObject的方法返回關於模式的所有的匹配。findall()返回所匹配的字串的一個列表:

p = re.compile(‘\d+’)
p.findall(‘12 drummers drumming, 11 pipers piping, 10 lords a-leaping’)
[‘12’, ‘11’, ‘10’]

finditer()方法返回一個作為指示器的MatchObject例項的序列。

iterator = p.finditer(‘12 drummers drumming, 11 … 10 …’)
iterator

for match in iterator:
… print match.span()

(0, 2)
(22, 24)
(29, 31)

3.4、模組級函式

你 是非得要產生一個RegexObject,然後呼叫它的方法;re模組也提供了頂級的函式來呼叫match(),search(),sub()等等。這些 函式使用與RegexObject方法相應的引數,使用正則表示式字串作為它們的第一個引數,並且仍然返回None或MatchObject例項。

print re.match(r’From\s+’, ‘Fromage amk’)
None
re.match(r’From\s+’, ‘From amk Thu May 14 19:12:10 1998’)

隱藏在下面的是這些函式簡單地為你產生一個RegexObject並呼叫它的適當的方法。它們也把被編譯了的物件儲存在快取中,以便於以後呼叫相同的正則表示式更快。

你 是使用模組級的函式還是自己得到RegexObject並呼叫它的方法呢?這個選擇依賴於正則表示式被使用的頻度,和你個人的程式碼風格。如果正則表示式僅 使用在程式碼中的一處,那麼模組級函式或許更方便。如果一個程式包含了大量的正則表示式,或在不同的位置要重複使用,那麼在一處集中所有的定義和提早在程式碼 的一部分中編譯所有的正則表示式是值得的。

3.5、編輯標誌

編輯標誌讓你修改正則表示式的一些工作方式。在re模組中標誌兩種名字都是有效的,長名如IGNORECASE,短名即一個字母如I。可以通過按位或(|)來指定多重標誌。例如,re.I|re.M設定I和M標誌。

下面是有效標誌及說明:

I
IGNORECASE
說明:執行不區分大小寫的匹配

L
LOCALE
說明:根據當前的場所使用\w,\W,\b,\B。
場 所是C庫的一個特性,它是為了在考慮到不同的語言差異時幫助寫程式。例如,如果你在處理一個法國文字,你可能想去寫\w+來匹配單詞,但是\w僅匹配字元 類別[A-Za-z];它不將匹配”é” 或 “ç”. 如果你的系統已恰當的配置並且法語場所已選擇,某個C函式將告訴程式”é”也被考慮為一個字母。 在編譯正則表示式時設定LOCALE標誌將導致編譯的結果物件為\w使用C函式,這是較慢的,但能如你所願的使用\w+去匹配法文。

M
MTLTILINE
說明:多行匹配
針對”^”,表示”^”除了匹配字串的開始位置,也匹配 ’\n’ 或 ’\r’ 之後的位置;
針對”""”除了匹配輸入字串的結束位置,也匹配 ’\n’ 或 ’\r’ 之前的位置

S
DOTALL
說明:使得”.”專用字元匹配任何字元,包括換行符;沒有這個標誌,”.”將匹配除了換行符以外的任何字元。