1. 程式人生 > >詳解 Python3 正則表達式(二)

詳解 Python3 正則表達式(二)

tps 數字 HERE art lock style 普通 則表達式 通過

上一篇:詳解 Python3 正則表達式(一)

本文翻譯自:https://docs.python.org/3.4/howto/regex.html

博主對此做了一些批註和修改 ^_^

技術分享圖片

使用正則表達式

現在我們開始來寫一些簡單的正則表達式吧。Python 通過 re 模塊為正則表達式引擎提供一個接口,同時允許你將正則表達式編譯成模式對象,並用它們來進行匹配。

批註:re 模塊是使用 C 語言編寫,所以效率比你用普通的字符串方法要高得多;將正則表達式進行編譯(compile)也是為了進一步提高效率;後邊我們會經常提到 “模式”,指的就是正則表達式被編譯成的模式對象。

編譯正則表達式

正則表達式被編譯為模式對象,該對象擁有各種方法供你操作字符串,如查找模式匹配或者執行字符串替換。

技術分享圖片

re.compile() 也可以接受 flags 參數,用於開啟各種特殊功能和語法變化,我們會在後邊一一介紹。

現在我們先來看個簡單的例子:

技術分享圖片

正則表達式作為一個字符串參數傳給 re.compile() 。由於正則表達式並不是 Python 的核心部分,因此沒有為它提供特殊的語法支持,所以正則表達式只能以字符串的形式表示。有些應用根本就不需要使用到正則表達式,所以 Python 社區的小夥伴們認為沒有必要將其納入 Python 的核心。相反,re 模塊僅僅是作為 C 擴展模塊包含在 Python 中,就像 socket 模塊和 zlib 模塊。

使用字符串來表示正則表達式保持了 Python 簡潔的一貫風格,但也因此有一些負面影響,下邊我們來談一談。

麻煩的反斜杠

上一篇中我們已經提到了,正則表達式使用 ‘\‘ 字符來使得一些普通的字符擁有特殊的能力(例如 \d 表示匹配任何十進制數字),或者剝奪一些特殊字符的能力(例如 \[ 表示匹配左括號 ‘[‘)。這會跟 Python 字符串中實現相同功能的字符發生沖突。

批註:挺拗口,接著看例子你就懂了~

現在的情況是,你需要在 LaTeX 文件中使用正則表達式匹配字符串 ‘\section‘ 。因為反斜杠作為需要匹配的特殊字符,所以你需要在它前邊多加一個反斜杠來剝奪它的特殊功能。所以我們會把正則表達式的字符寫成 ‘\\section‘ 。

但不要忘了,Python 在字符串同樣使用反斜杠來表示特殊意義。因此,如果我們想將 ‘\\section‘ 完整地傳給 re.compile(),我們需要再次添加兩個反斜杠 ......

匹配字符 匹配階段
\section 需要匹配的字符串
\\section 正則表達式使用 ‘\\‘ 表示匹配字符 ‘\‘
\\\\section 不巧,Python 字符串也使用 ‘\\‘ 表示字符 ‘\‘

簡而言之,為了匹配反斜杠這個字符,我們需要在字符串中使用四個反斜杠才行。所以,在正則表達式中頻繁地使用反斜杠,會造成反斜杠風暴,進而導致你的字符串極其難懂。

解決方法是使用 Python 的原始字符串來表示正則表達式(就是在字符串前邊加上 r,大家還記得吧 ... ):

正則字符串 原始字符串
“ab*” r"ab*"
"\\\\section" r"\\section"
"\\w+\\s+\\1" r"\w+\s+\1"

批註:強烈建議使用原始字符串來表達正則表達式。

實現匹配

當你將正則表達式編譯之後,你就得到一個模式對象。那你拿它可以做什麽呢?模式對象擁有很多方法和屬性,我們下邊列舉最重要的幾個來講:

方法 功能
match() 判斷一個正則表達式是否從開始處匹配一個字符串
search() 遍歷字符串,找到正則表達式匹配的第一個位置
findall() 遍歷字符串,找到正則表達式匹配的所有位置,並以列表的形式返回
finditer() 遍歷字符串,找到正則表達式匹配的所有位置,並以叠代器的形式返回

如果沒有找到任何匹配的話,match() 和 search() 會返回 None;如果匹配成功,則會返回一個匹配對象(match object),包含所有匹配的信息:例如從哪兒開始,到哪兒結束,匹配的子字符串等等。

接下來我們一步步講解:

技術分享圖片

現在,你可以嘗試使用正則表達式 [a-z]+ 去匹配各種字符串。

例如:

技術分享圖片

因為 + 表示匹配一次或者多次,所以空字符串不能被匹配。因此,match() 返回 None。

我們再嘗試一個可以匹配的字符串:

技術分享圖片

在這個例子中,match() 返回一個匹配對象,我們將其存放在變量 m 中,以便日後使用。

接下來我們來看看匹配對象裏邊有哪些信息吧。匹配對象包含了很多方法和屬性,以下幾個是最重要的:

方法 功能
group() 返回匹配的字符串
start() 返回匹配的開始位置
end() 返回匹配的結束位置
span() 返回一個元組表示匹配位置(開始,結束)

大家看:

技術分享圖片

由於 match() 只檢查正則表達式是否在字符串的起始位置匹配,所以 start() 總是返回 0 。

然而,search() 方法可就不一樣咯:

技術分享圖片

在實際應用中,最常用的方法是將匹配對象存放在一個局部變量中,並檢查其返回值是否為 None 。

形式通常如下:

p = re.compile(...)
m = p.match(‘String goes here‘)
if m:
    print(‘Match found:‘, m.group())
else:
    print(‘No match‘)

有兩個方法可以返回所有的匹配結果,一個是 findall(),一個是 finditer() 。

findall() 返回的是一個列表:

技術分享圖片

findall() 需要在返回前先創建一個列表,而 finditer() 則是將匹配對象作為一個叠代器返回:

技術分享圖片

批註:如果列表很大,那麽返回叠代器的效率要高很多。

(本文完)

下一篇:詳解 Python3 正則表達式(三)

如果你喜歡這篇文章,請通過下方「評論」給我鼓勵哦 ^_^

詳解 Python3 正則表達式(二)