Python 爬蟲十六式 - 第七式:正則的藝術

Connor_Zhang發表於2019-02-12

RE:用匹配來演繹程式設計的藝術

學習一時爽,一直學習一直爽

  Hello,大家好,我是 Connor,一個個從無到有的技術小白。上一次我們說到了 pyquery 今天我們將迎來我們資料匹配部分的最後一位重量級人物,也是程式語言中普及率最高的一個東西,它就是正則。正則長期以來佔據著程式設計新手的禁忌之地,大家對它是又愛又恨。今天,我們將揭開他神祕的面紗,直面正則,並助你征服它,讓它成為你的得力助手!

Python 爬蟲十六式 - 第七式:正則的藝術

1. 正則的介紹

  由於正則並不是 Python 所獨有的內容,本文大部分會以正則的角度來進行描述和講解,而不侷限於 re 庫,文章會穿插以 re 為例,對正則的例子進行講解。

1.1 正則的起源

  想要徹底掌握正則,就要從頭到尾的瞭解它。那麼正則是如何誕生的呢?這要追溯到上世紀人們對人類神經系統如何工作的早期研究。兩位神經生理學家研究出一種數學方式來描述這些神經網路。具體叫什麼我就不說了。

Python 爬蟲十六式 - 第七式:正則的藝術

  1956 年, 一位數學家在上面兩位神經生理學家早期工作的基礎上,發表了一篇標題為“神經網事件的表示法”的論文,引入了正規表示式的概念。正規表示式就是用來描述他稱為“正則集的代數”的表示式,因此採用“正規表示式”這個術語。

  隨後他們發現可以將這一研究成果廣泛的應用於其它領域的研究。Ken Thompson 使用它來進行一些早期的計算搜尋演算法的一些研究,Ken Thompson 是 Unix 的主要發明人。正規表示式的第一個實用應用程式就是 Unix 中的 qed 編輯器。

  然後,正規表示式在各種計算機語言或各種應用領域得到了廣大的應用和發展,演變成為目前計算機技術森林中的一隻形神美麗且聲音動聽的百靈鳥。到目前正規表示式在基於文字的編輯器和搜尋工具中依然佔據這一個非常重要的地位。

  在最近的六十年中,正規表示式逐漸從模糊而深奧的數學概念,發展成為在計算機各類工具和軟體包應用中的主要功能。不僅僅眾多UNIX工具支援正規表示式,近二十年來,在 Windows 的陣營下,正規表示式的思想和應用在大部分 Windows 開發者工具包中得到支援和嵌入應用!

  Windows 系列產品對正規表示式的支援發展到無與倫比的高度,目前幾乎所有 Microsoft 開發者和所有.NET語言都可以使用正規表示式。包括 Python、Java、JavaScript、Go 等非 Windows 系列的產品也對正則進行了支援,這無疑將正則變成了程式設計界的寵兒,可以說得正則者得天下!

  所以,看到這裡是不是想要迫不及待地來學會正則了???讓我們一起來看看正則的概念:


1.2 正則的概念

  正規表示式是對字串操作的一種邏輯公式,就是用事先定義好的一些特定字元、及這些特定字元的組合,組成一個“規則字串”,這個“規則字串”用來表達對字串的一種過濾邏輯。

  Emmn… 看了這麼官方的描述還是有些懵逼,說白了正規表示式就是通過一些指定好的特殊字元來代替某種字元。舉個例子:大家小時候都玩過撲克遊戲排火車,就是當你現在排的牌和前面的任意一張大小相同的時候,無論中間有多少,有什麼牌你都可以獲取這中間所有的牌。正則和這個類似,無視中間所有的東西,只要滿足你這個規則,就可以取出中間所有的內容!

  不知道我的例子夠不夠清晰,反正我絞盡腦汁也只想到了這一個比較像的例子,如果你有什麼更好的例子,可以留言或評論,我將引用你的例子。

  說完了正則的概念,我們再來看看正則有哪些特點吧!


1.3 正則的特點

  正規表示式有如下的特點:

  1. 靈活性、邏輯性和功能性非常的強;
  2. 可以迅速地用極簡單的方式達到字串的複雜控制。
  3. 適用於任何字串

2. 正規表示式的基礎知識

  這裡往後都是基礎的東西,如果你覺得你都懂了想直接看Python的re庫請 點選這裡>>

  既然大概瞭解了正則的歷史以及他的功能和特點,那麼讓我們從正規表示式的基礎知識來開始學習吧。大多數教程都是從元字元開始的,但是他們忽略了一些最基礎的東西,這些東西對於初級運用或許沒有任何關係,但是當你要使用到高階用法的時候很可能會造成混亂,甚至是遺忘,所以我們在開始前先來說一說正則的基礎知識:

2.1 字串的位置講解

  在我們的印象中,游標的位置就是在字元之後的,但是實際上在底層,游標指的並不是當前字元的位置,而是游標前面的這個位置,如圖:

Python 爬蟲十六式 - 第七式:正則的藝術

  真實的游標位置指的是游標之前的這個字母,是這個字母 e 的位置,所以在一個長度為 n 的字串中,總共有 n + 1 個位置。例如:

(0)a(1)b(2)c(3)
複製程式碼

在這個長度為 3 的字串 abc 中,一共有 (0)(1)(2)(3)四個位置


2.2 佔有字元和零寬度

  可能現在說佔有字元和零寬度會讓你感覺有些不知所措,但是當你看完後面的內之後再反過來看佔有字元和零寬度的時候你就會恍然大悟,將這兩個概念瞭然於心了。

  正規表示式匹配過程中,如果子表示式匹配到東西,而並非是一個位置,並最終儲存到匹配的結果當中。這樣的就稱為佔有字元,而只匹配一個位置,或者是匹配的內容並不儲存到匹配結果中,這種就稱作零寬度,佔有字元是互斥的,零寬度是非互斥的。也就是一個字元,同一時間只能由一個子表示式匹配,而一個位置,卻可以同時由多個零寬度的子表示式匹配。


2.3 正規表示式的控制權與傳動

  正規表示式由左到右依次進行匹配,通常情況下是由一個表示式取得控制權,從字串的的某個位置進行匹配,一個子表示式開始嘗試匹配的位置,是從前一個匹配成功的結束位置開始的。


3. 正規表示式的語法

3.1 正規表示式的元字元

  正規表示式的元字元是正規表示式的根本,所有的正規表示式都有元字元組成,正規表示式的元字元包括下列幾種:

3.1.1 基本元字元

字元 描述
. 匹配除換行符外的任意字元
* 匹配0個或多個符合表示式的字元
? 匹配0個或1個符合表示式的字元
+ 匹配1個或多個符合表示式的字元
[...] 匹配方括號內的任意字元
[^...] 匹配除方括號字元內的任意字元

3.1.2 轉義元字元

字元 描述
\ 用於轉義下一個字元
\A 僅匹配字串的開頭
\b 匹配一個單詞的邊界
\B 匹配非單詞邊界
\cX 匹配指明的控制字元
\d 匹配一個數字,等價於[0-9]
\D 匹配一個非數字,等價於[^0-9]
\f 匹配一個換頁符,等價於\x0c和\cL
\n 匹配一個換行符,等價於\x0a和\cJ
\t 匹配一個製表符,等價於\x09和\cI
\r 匹配一個回車符,等價於\x0d和\cM
\s 匹配 一個不可見的字元
\S 匹配一個可見的字元
\v 匹配一個垂直製表符,等價於\x0b和\cK
\w 匹配包括下劃線的任何單詞字元
\W 匹配任何非單詞字元
\Z 僅匹配字串的末尾
\xn 匹配轉移為\xn的十六進位制轉義字元
\un 匹配一個Unicode轉義字元

3.1.3 限定類元字元

字元 描述
{n} 匹配確定的n個字元
{n,} 匹配至少n個字元
{n,m} 匹配至少n個字元,至多m個字元
| 或符號,用於連線多個表示式
- 範圍符,只能用於方括號中,如[a-z]
^ 匹配字串的開頭,在方括號中表示取反
$ 匹配字串的末尾
(parameter) 將括號內的內容進行匹配並分組
(?!parameter) 正向否定預查,匹配不是parameter的內容
(?=parameter) 正向肯定預查,匹配是parameter的內容
(?:parameter) 匹配parameter獲取匹配結果
(?<=parameter) 反向肯定預查,在任何匹配的paraemter處開始匹配字串
(?<!parameter) 反向否定預查,在任何不符合parameter的地方開始匹配字串

  只是在這裡向你羅列元字元你是不會懂如何使用正則的,請稍安勿躁,稍後我們將以 Python 中的正則為例,為大家逐一展示各種元字元的用法。如果你比較急切,請點選這裡來快速檢視 re 庫的使用方法。瞭解了元字元,我們再來認識一下可列印字元與非列印字元:


3.2 列印字元與非列印字元

3.2.1 列印字元

  如你所見,你在網上瀏覽到的所有的字元,這包括所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號。這些全部可見的字元都叫做可列印字元

3.2.2 非列印字元

  非列印字元也可以是正規表示式的組成部分。下表列出了表示非列印字元的轉義序列:

字元 描述
\cx 匹配由x指明的控制字元。
\f 匹配一個換頁符。等價於 \x0c 和 \cL。
\n 匹配一個換行符。等價於 \x0a 和 \cJ。
\r 匹配一個回車符。等價於 \x0d 和 \cM。
\s 匹配任何空白字元,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。
\S 匹配任何非空白字元。等價於 [^\f\n\r\t\v ]
\t 匹配一個製表符。等價於 \x09 和 \cI。
\v 匹配一個垂直製表符。等價於 \x0b 和 \cK。

  列印字元和非列印字元非常易懂,沒什麼難點,一筆帶過,下面我們來看看運算子的優先順序:


3.3 正規表示式運算子的優先順序

  正規表示式從左到右進行計算,並遵循優先順序順序,這與算術表示式非常類似。相同優先順序的從左到右進行運算,不同優先順序的運算先高後低。下表從最高到最低說明了各種正規表示式運算子的優先順序順序:

運算子 描述
\ 轉義符
(), (?:), (?=), [] 圓括號和方括號
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \任何元字元、任何字元 定位點和序列(即:位置和順序)
| 替換,"或"操作字元

  運算優先順序非常類似於四則運算,沒什麼好說的,下面我們來看看正則的匹配模式:


3.4 正則的匹配模式(表示式修飾符)

  正規表示式有時候不只是需要使用簡單的正則語句,有時候還需要挑選合適的匹配模式(表示式修飾符),通過這些不同的匹配模式,可以提升匹配的效率。正則的匹配模式如表:

模式 描述
/a 強制從字串頭開頭進行匹配
/i 不區分大小寫匹配
/g 全域性匹配
/m 多行匹配
/s 特殊字元匹配
/u 不重複匹配
/x 忽略模式中的空白

  到這裡就介紹完元字元了,如果你想直接看元字元的使用示例,請 點選這裡>>

4. Python 的正則庫 -- re庫

  正則被廣大程式語言所支援,Python也不例外,Python 官方為我們封裝了 re 庫來支援正則的使用,下面我們一起來走進 Python 的 正則庫--re庫:

4.1 Python 中的正則匹配模式

  Python 的正則也是正則,所以它也有匹配模式。但這匹配模式又有些不同於正則的表達方式,我們來看一看:

修飾符 描述
re.A 強制從字串頭開始匹配
re.I 使匹配對大小寫不敏感
re.L 做本地化識別(locale-aware)匹配
re.M 多行匹配,影響 ^ 和 $
re.S 使 . 匹配包括換行在內的所有字元
re.U 根據Unicode字符集解析字元
re.X 該標誌通過給予你更靈活的格式以便你將正規表示式寫得更易於理解。

  可以看到,匹配模式並不再是 /* 來進行表示了,而是變成了 re.* 來進行表示了。


4.2 Python 中的正則常用方法

   Python 既然是一種語言,那麼它定然不會讓我們傻敷敷的去使用,Python 為我們封裝好了方法,我們來逐一看一下都有哪些方法吧:

4.2.1 compile()

re.compile(pattern, flags=0)
複製程式碼

  這個方法用來將正規表示式進行編譯,返回一個Pattern物件。這麼說你一定還是很懵逼,我們來舉個例子:

import re
string = "Learning makes a good man better and ill man worse."
pattern = re.compile(r"m\w+")
result = pattern.findall(string)
print(result)
複製程式碼

返回結果:

['makes', 'man', 'man']
複製程式碼

  這樣就顯而易見了,先將正規表示式進行編譯,在下次使用的時候直接給編譯好的正規表示式一個字串讓它去匹配就好了。這樣做的好處是提高了效能,如果你要處理大文件,建議你這樣使用。

4.2.2 escape()

escape(pattern)
複製程式碼

  這個方法可以用來匹配除 ASCII字元,數字和特殊字元 ‘_’ 以外的所有字元。官方的說法就是不一樣,這個東西有時候真的挺讓人懵逼的,簡單來說,這個方法就是用來消除字串中的任何特殊字元效果的。

  我舉個例子你就明白了。有時候問哦們在匹配網址的時候,因為 ‘.’ 是特殊字元,所以有些時候我們無法成功的進行匹配,我們需要轉義後再進行匹配,大部分人的操作是這樣的:

import re
string = "www.baidu.com"
result = re.findall(r"baidu\.com", string)
print(result)
複製程式碼

  這樣做確實可以達到我們想要的效果,但是對於想要玩騷操作的我們來說,這樣太 Low 了,所以就有了這樣的方式:

import re
string = "www.biadu.com"
result = re.findall(re.escape("baidu.com"), string)
print(result)
複製程式碼

  這樣一來,我們就省去了寫轉義的麻煩步驟,案例中需要轉移的內容較少,可能看不出有什麼優勢,但是當你匹配大量需要轉移的內容的時候,這樣做不僅可以省去打轉義字元的麻煩,而且也防止我們漏打,錯打轉義字元。

  當然,你也要注意一點,使用這個方法會消除一切特殊字元的特殊效果,使用這種方法匹配具有一定的侷限性,不能再進行模糊匹配了,請按需使用。

4.2.3 findall()

findall(pattern,string,flags = 0複製程式碼

  通過這個方法匹配出來的是字串中所有非重疊匹配的列表。老規矩,舉個例子:

import re
string = "Learning makes a good man better and ill man worse."
result = re.findall(r'm\w+', string)
print(result)
複製程式碼

執行結果:

	['makes', 'man', 'man']
複製程式碼

  

4.2.4 finditer()

finditer(pattern, string, flags=0)
複製程式碼

  通過這個方法可以將字串中所有非重疊匹配上返回迭代器。對於每個匹配,迭代器返回一個匹配物件,匹配結果中包含有空物件。

  簡單的說,就是返回一個可迭代的 Objct 物件,這是它和 findall() 方法唯一的區別。 我們舉個例子:

import re
string = """  QQ郵箱:  123456789@qq.com
            網易郵箱: 123456789@163.com
             126郵箱: 123456789@126.com"""
ls = re.finditer(r"(\d+@\w+.com)", string, re.S)
print(type(ls))
for item in ls:
    print(item.group())
複製程式碼

執行結果如下:

<class 'callable_iterator'>
123456789@qq.com
123456789@163.com
123456789@126.com
複製程式碼

  生成的可迭代的 Object 物件中,內部物件都為 SRE_Match 物件,該物件不可直接提取匹配的內容,需要通過 group() 方法來進行提取。

4.2.5 fullmatch()

fullmatch(pattern, string, flags=0)
複製程式碼

  通過這個方法可以用來判斷整個字串是否匹配規則,如果符合規則則返回 match object。不符合則返回 None。舉個例子:

import re
string = """QQ郵箱:  123456789@qq.com"""
ls = re.fullmatch(r"QQ郵箱:  123456789@qq.com", string, re.S)
print(ls.group())
複製程式碼

執行結果如下:

QQ郵箱:  123456789@qq.com
複製程式碼

如果我們隨意改變一下規則:

import re
string = """QQ郵箱:  123456789@qq.com"""
ls = re.fullmatch(r"QQ郵箱", string, re.S)
print(ls)
複製程式碼

執行結果:

None
複製程式碼

  可以看得出,只有當整個字串都符合匹配規則的時候才能匹配到東西,否則的話返回的是 None

4.2.6 match()

match(pattern, string, flags=0)
複製程式碼

  使用這個方法可以嘗試在字串的開頭進行匹配,返回匹配物件,如果未找到匹配,則返回None。

  你應該注意到了,它是在字串的開頭進行匹配的,如果你還是不太清楚,那我們接著來看例子:

import re
string = """QQ郵箱:123456789@qq.com"""
ls = re.match(r"QQ郵箱", string, re.S)
print(ls)
複製程式碼

執行結果如下:

<_sre.SRE_Match object; span=(0, 4), match='QQ郵箱'>
複製程式碼

因為我們匹配的法則在開頭有,如果我們換個規則的話:

import re
string = """QQ郵箱:123456789@qq.com"""
ls = re.match(r"\d+", string, re.S)
print(ls)
複製程式碼

執行結果:

None
複製程式碼

  按照我們的想法它應該會匹配到@前面的一串數字吧?但是實際上它並沒有匹配到。這就是所謂的在字串的開頭進行匹配。

4.2.7 purge()

  通過這個方法可以清除正規表示式的快取。這個方法貌似沒有啥好說的 …

Python 爬蟲十六式 - 第七式:正則的藝術

4.2.8 search()

search(pattern, string, flags=0)
複製程式碼

  搜尋整個字串以匹配符合規則的字串,如果有則返回匹配物件,如果沒有則返回None。前面說的 match() 方法是隻在頭部進行匹配,而 search() 方法可以在字串中的任意位置進行匹配。例如:

import re
string = """QQ郵箱:123456789@qq.com"""
ls = re.search(r"\d+", string, re.S)
print(ls)
複製程式碼

執行結果如下:

<_sre.SRE_Match object; span=(5, 14), match='123456789'>
複製程式碼

  可以看的出,沒有在字串首部的字元也被匹配出來了。相比 match() 方法,search() 方法,findall() 方法要用的更多些。

4.2.9 split()

split(pattern,string,maxsplit = 0,flags = 0複製程式碼

  看到這個方法我想大家第一時間想到的是字串中的 split() 方法,恭喜你,猜對了,這個方法和 字串中自帶的 split() 方法大同小異,這個方法增加的功能是可以通過正規表示式來進行分割。例如:

首先舉一個都能理解的功能:

import re
string = """abc,123456789,@qq.com"""
ls = re.split(r",", string)
print(ls)
複製程式碼

執行結果:

['abc', '123456789', '@qq.com']
複製程式碼

  可以看得出,現在的分割方法和 字串中自帶的 split() 方法沒有什麼區別。下面我們再看多出來的用法:

import re
string = """abc123456789@qq.com"""
ls = re.split(r"\d+", string)
print(ls)
複製程式碼

執行結果:

['abc', '@qq.com']
複製程式碼

  可以看得出,該方法將 數字作為分割依據進行了分割。如果你足夠細心的話,你會發現這個方法還有一個引數,叫 maxsplit 這個方法代表著最大分割次數。比如:

import re
string = """abc,123456789,@qq.com"""
ls = re.split(r",", string, 1)
print(ls)
複製程式碼

執行結果如下:

['abc', '123456789,@qq.com']
複製程式碼

  可以看到它只進行了一次分割,maxsplit 就是用來控制分割次數的,分割從左到右依次進行分割。分割 maxsplit 次。

4.2.10 sub()

sub(pattern,repl,string,count = 0,flags = 0複製程式碼

  將所有符合規則的字串替換成 repl。最多替換 count個,預設全部替換。這是我個人認為正則中除了 findall() 方法外最有用的方法了。批量替換超級有用!!!

Python 爬蟲十六式 - 第七式:正則的藝術

  咳咳,激動了啊,下面我們來說說這個方法的使用:

import re
string = """abc123456789@qq.com"""
ls = re.sub(r"456", "abc", string)
print(ls)
複製程式碼

執行結果如下:

abc123abc789@qq.com
複製程式碼

  一下就把字串中的 456 給替換成 abc了,賊帶勁。用了這個方法你還想用 replace方法嗎?那個方法多傻,如果你不覺得,一會我會讓你認同我的觀點的。我們先往下說,sub() 方法也有一個計數引數 count,我們可以通過給它賦值來指定替換個數。比如:

import re
string = """abc12abc67abc@qq.com"""
ls = re.sub(r"abc", "---", string, 2)
print(ls)
複製程式碼

執行結果:

---12---67abc@qq.com
複製程式碼

  在上面的程式中我們指定了替換個數2,所以結果中只替換了兩個 abc,並沒有全部替換。如果不指定 count 引數的話,預設會進行全部替換。

4.2.11 subn()

subn(pattern,repl,string,count = 0,flags = 0複製程式碼

  這個方法和 sub() 方法沒有什麼本質上的區別,唯一的不同就是它返回的是一個元組,這個元組包含有兩個內容,(1)替換後的字串,(2)整個字串中的替換次數。舉個例子:

import re
string = """abc12abc67abc@qq.com"""
ls = re.subn(r"abc", "---", string)
print(ls)
複製程式碼

執行結果如下:

('---12---67---@qq.com', 3)
複製程式碼

4.2.12 template()

template(pattern, flags=0)
複製程式碼

  這個方法我查了很多資料,國內的網站並沒有幾個人寫這個方法的,可能有寫的,但是沒有用這個標題來進行發表吧,總之我沒有找到什麼詳細的資料,但是通過他的官方解釋:“編譯模板模式,返回模式物件” 可以看得出它返回的是一個模式物件,和 re.compile() 方法類似,返回的都是一個模式物件。應該用法和 re.complie()相似。

  但是我查閱了國外的網站,大家有提到說發現這個函式,但是並沒有發現有什麼用處。大家說,可能這個函式並未實現預期想要的功能,或者這個函式出現了什麼問題而關閉了。所以只能暫時停留在這個狀態。當然平時我們也用不到這個函式

  我通過自己的琢磨,自己的嘗試,發現這個函式大部分函式功能是和 compile() 方法相同的。比如:

import re
abc = re.template(r"abc", re.I)
string = "abcasdfadsfABCasdfabcasdfasdf"
result = abc.findall(string)
print(result)
複製程式碼

執行結果如下:

['abc', 'ABC', 'abc']
複製程式碼

但是最主要的問題是,該方法禁用所有的特殊字元,即re的元字元,比如:

import re
abc = re.template(r"\d+", re.I)
string = "abcasdfadsfABCasdfabcasdfasdf"
result = abc.findall(string)
print(result)
複製程式碼

執行結果如下:

Traceback (most recent call last):
File "G:/Python/PyWin/test.py", line 2, in <module>
    abc = re.template(r"\d+", re.I)
    ....
複製程式碼

這個情況下就直接報錯了。所以我想不出來這個函式有什麼作用。之所以寫出來就當給大家開眼了。如果真的需要使用模板的話,還是建議大家使用 re.compile() 方法來進行操作。

好了,這就是 Python 正則庫 re 中的所有函式了。下面我還有幾個內容要給大家說


4.3 re 中的 Pattern 物件

   這個Pattern 我為什麼不在講方法之前說呢,就是怕你們不明白,讓我一下子給弄暈了,所以我選擇在講完所有方法之後再說。這樣的話有些人不需要了解這麼深,直接找到他們想要的方法,直接去使用就好了。這樣也方便他們使用…

Python 爬蟲十六式 - 第七式:正則的藝術

  好好,我們現在來說 **Pattern **物件。那什麼是 Pattern 物件呢?如果你仔細看之前我寫的方法的話,你會發現幾乎每個正則的方法裡都有一個 Pattern 引數 ,回想一下那個引數寫的什麼? 對,Pattern物件就是我們編譯後的正則規則。

  之前我們在講 re.compile() 方法的時候說過,這個方法返回的就是一個 Pattern物件。這個物件幾乎可以執行 re 中的所有方法。是比較簡單的一個物件。相信大家都可以理解。我覺得也沒啥好說的了。

Python 爬蟲十六式 - 第七式:正則的藝術

re 中的 Match 物件

  Emmn….說完了 Pattern物件我們現在來說說 Match 物件。

Python 爬蟲十六式 - 第七式:正則的藝術

  好的好的,我一定好好說這個….這個Match 物件呢,是 re構建的一個物件。我們通過 match()fullmatch()search()fjinditer(),這幾種方法返回的都是 Match 物件。我們來看看一個 Match 物件中都包含什麼:

<_sre.SRE_Match object; span=(3, 6), match='abc'>
複製程式碼
  • span 指的是匹配到的字串在字串中的位置。例中的 3,6 分別是開始位置和結束位置。
  • match 指的是匹配到的內容

下面我們來說說 Match 物件中常用的方法:

方法 解釋
end([group]) 獲取組的結束位置
expand(string) 將match物件中的字串替換成指定字串
group(index) 某個組匹配的結果
groupdict() 返回組名作為key,每個分組的匹配結果作為value的字典
groups() 所有分組的匹配結果,每個分組組成的結果以列表返回
start([group]) 獲取組的開始位置
span([group]) 獲取組的開始和結束位置

  這就是 Match 物件的所有內容了。還是很容易掌握的嘛。


5. 正規表示式所有元字元的示例

  講完了正規表示式了,也講完了python中的 re庫,下面我們來將之前說好的元字元的示例逐一展示出來:

5.1 基本元字元的示例

字元 描述
. 匹配除換行符外的任意字元
* 匹配0個或多個符合表示式的字元
? 匹配0個或1個符合表示式的字元
+ 匹配1個或多個符合表示式的字元
[...] 匹配方括號內的任意字元
[^...] 匹配除方括號字元內的任意字元

元字元 “.” 的示例:

import re
string = "abcdefghigklmnopqrstuvwxyz1234567890"
result = re.match(r".bc", string)
print(result.group())

執行結果:
abc
複製程式碼

元字元 “*” 的示例:

import re
string = "abcdefghigklmnopqrstuvwxyz1234567890"
result = re.search(r"(a.*g)", string)
print(result.group())

執行結果:
abcdefg
複製程式碼

元字元 “?” 的示例:

import re
string = "aaabcdefg"
result = re.search(r"a?b", string)
print(result.group())

執行結果:
ab
複製程式碼

元字元 “+” 的示例:

import re
string = "aaabcdefg"
result = re.search(r"a+", string)
print(result.group())

執行結果:
aaa
複製程式碼

元字元 “[…]” 的示例:

import re
string = "aaabcdefg123456789"
result = re.findall(r"[\D]+", string)
print(result)

執行結果:
['aaabcdefg']
複製程式碼

元字元 “[^...]” 的示例:

import re
string = "aaabcdefg123456789"
result = re.findall(r"[^\d]+", string)
print(result)

執行結果:
['aaabcdefg']
複製程式碼

5.2 轉義元字元的示例

字元 描述
\ 用於轉義下一個字元
\A 僅匹配字串的開頭
\b 匹配一個單詞的邊界
\B 匹配非單詞邊界
\cX 匹配指明的控制字元
\d 匹配一個數字,等價於[0-9]
\D 匹配一個非數字,等價於0-9
\f 匹配一個換頁符,等價於\x0c和\cL
\n 匹配一個換行符,等價於\x0a和\cJ
\t 匹配一個製表符,等價於\x09和\cI
\r 匹配一個回車符,等價於\x0d和\cM
\s 匹配 一個不可見的字元
\S 匹配一個可見的字元
\v 匹配一個垂直製表符,等價於\x0b和\cK
\w 匹配包括下劃線的任何單詞字元
\W 匹配任何非單詞字元
\Z 僅匹配字串的末尾
\xn 匹配轉移為\xn的十六進位制轉義字元
\un 匹配一個Unicode轉義字元

元字元 “\” 的示例:

import re
string = "aaabcdefg123456789"
result = re.findall(r"\d+", string)
print(result)

執行結果:
['123456789']
複製程式碼

元字元 “\A” 的示例

import re
string = "aaabcdefg123456789"
result = re.findall(r"\A\w", string)
print(result)

執行結果:
['a']
複製程式碼

元字元 “\b” 的示例

import re
string = "aaabcdefg123456789"
result = re.findall(r"\b\w{5}", string)
print(result)

執行結果:
['aaabc']
複製程式碼

元字元 “\B” 的示例

import re
string = "I'm the king of the world"
result = re.findall(r"\B\w+", string)
print(result)

執行結果:
['he', 'ing', 'f', 'he', 'orld']
複製程式碼

元字元 “\d” 的示例

import re
string = "abcdefg1234567"
result = re.findall(r"\d+", string, re.S)
print(result)

執行結果:
['1234567']
複製程式碼

元字元 “\D” 的示例

import re
string = "abcdefg1234567"
result = re.findall(r"\D+", string, re.S)
print(result)

執行結果:
['abcdefg']
複製程式碼

元字元 “\f” 的示例

import re
string = "abcdefg\f1234567"
result = re.findall(r"\f", string, re.S)
print(result)

執行結果:
['\x0c']
複製程式碼

元字元 “\n” 的示例

import re
string = "abcdefg\n1234567"
result = re.findall(r"\n\d+", string, re.S)
print(result)

執行結果:
['\n1234567']
複製程式碼

元字元 “\t” 的示例

import re
string = "abcdefg\t1234567"
result = re.findall(r"\t", string, re.S)
print(result)

執行結果:
['\t']
複製程式碼

元字元 “\r” 的示例

import re
string = """abcdefg\r1234567"""
print(string)
result = re.findall(r"\r", string, re.S)
print(result)

執行結果:
1234567
['\r']
複製程式碼

元字元 “\s” 的示例

import re
string = """abcdefg\n1234567"""
result = re.findall(r"\s", string, re.S)
print(result)

執行結果:
['\n']
複製程式碼

元字元 “\S” 的示例

import re
string = """abcdefg\n1234567"""
result = re.findall(r"\S+", string, re.S)
print(result)

執行結果:
['abcdefg', '1234567']
複製程式碼

元字元 “\w” 的示例

import re
string = """I_m the king of the world"""
result = re.findall(r"\w+", string, re.S)
print(result)

執行結果:
['I_m', 'the', 'king', 'of', 'the', 'world']
複製程式碼

元字元 “\W” 的示例

import re
string = """I'm the king of the world"""
result = re.findall(r"\W+", string, re.S)
print(result)

執行結果:
["'", ' ', ' ', ' ', ' ', ' ']
複製程式碼

元字元 “\Z” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"\w{2}\Z", string, re.S)
print(result)

執行結果:
['yz']
複製程式碼

元字元 “\xn” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"\x77", string, re.S)
print(result)

執行結果:
['w']
複製程式碼

元字元 “\un” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"\u0077", string, re.S)
print(result)

執行結果:
['w']
複製程式碼

5.3 限定類元字元的示例

字元 描述
{n} 匹配確定的n個字元
{n,} 匹配至少n個字元
{n,m} 匹配至少n個字元,至多m個字元
| 或符號,用於連線多個表示式
- 範圍符,只能用於方括號中,如[a-z]
^ 匹配字串的開頭,在方括號中表示取反
$ 匹配字串的末尾
(parameter) 將括號內的內容進行匹配並分組
(?!parameter) 正向否定預查,匹配不是parameter的內容
(?=parameter) 正向肯定預查,匹配是parameter的內容
(?:parameter) 匹配parameter獲取匹配結果
(?<=parameter) 反向肯定預查,在任何匹配的paraemter處開始匹配字串
(?<!parameter) 反向否定預查,在任何不符合parameter的地方開始匹配字串

元字元 “{n}” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"u\w{2}", string, re.S)
print(result)

執行結果:
['uvw']
複製程式碼

元字元 “{n,}” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"u\w{3,}", string, re.S)
print(result)

執行結果:
['uvwxyz']
複製程式碼

元字元 “{n,m}” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"u\w{1,3}", string, re.S)
print(result)

執行結果:
['uvwx']
複製程式碼

元字元 “|” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"u\w|x\w", string, re.S)
print(result)

執行結果:
['uv', 'xy']
複製程式碼

元字元 “-” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"[a-z]+", string, re.S)
print(result)

執行結果:
['uvwxyz']
複製程式碼

元字元 “^” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"[^1-9]+", string, re.S)
print(result)

執行結果:
['uvwxyz']
複製程式碼

元字元 “$” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"\w{3}$", string, re.S)
print(result)

執行結果:
['xyz']
複製程式碼

元字元 “(parameter)” 的示例

import re
string = """uvwxyz"""
result = re.findall(r"u(\w{2})x(\w{2})", string, re.S)
print(result)

執行結果:
[('vw', 'yz')]
複製程式碼

元字元 “(?=parameter)” 的示例

import re
string = """COD4 COD6 COD8"""
result = re.findall(r"COD.(?=4)", string, re.S) #匹配.=4的字串COD
print(result)

執行結果:
['COD4']
複製程式碼

元字元 “(?!parameter)” 的示例

import re
string = """COD4 COD6 COD8 """
result = re.findall(r"COD.(?!4)", string, re.S) # 匹配 .!=4的字串
print(result)

執行結果:
['COD6', 'COD8']
複製程式碼

元字元 “(?:parameter)” 的示例

import re
string = """COD4COD6COD8"""
result = re.findall(r".*?(?:4)", string, re.S) # 匹配獲取引數為4的字串
print(result)

執行結果:
['COD4']
複製程式碼

元字元 “(?<=parameter)” 的示例

import re
string = """COD4 COD6 COD8 """
result = re.findall(r"COD.(?<=4)", string, re.S) # 從右向左匹配.=4的字串
print(result)

執行結果:
['COD4']
複製程式碼

元字元 “(?<!parameter)” 的示例

import re
string = """COD4 COD6 COD8 """
result = re.findall(r"COD.(?<!4)", string, re.S) # 從右向左匹配.!=4的字串
print(result)

執行結果:
['COD6', 'COD8']
複製程式碼

  到這裡我們就把正則的所有元字元的示例就都演示完了。我所演示的是最基礎的用法,如果真的想要使用高階的用法,還是要自己多進行嘗試,多練習。練習的多了使用正則才會信手拈來。


下期預告

  你看你說了這麼多,又是訪問網頁,又是獲取資料的,說了半天我們還是不知道怎麼用。我會只是單獨的給你們說這麼簡單嗎?當然會有練習的啦。敬請期待下一期:Python 爬蟲十六式 - 第八式:例項解析-全書網!我們通過全書網來讓你一下吸收前面的知識。

Python 爬蟲十六式 - 第七式:正則的藝術

  好了,這就是今天的內容了,不知道你又學會了多少呢?我是Connor,一個從無到有的技術小白,願你在前進的道路上堅持不懈!

學習一時爽,一直學習一直爽!

系列文章

Python 爬蟲十六式 - 第一式:HTTP協議 >>>
Python 爬蟲十六式 - 第二式:urllib 與 urllib3 >>>
Python 爬蟲十六式 - 第三式:Requests的用法 >>>
Python 爬蟲十六式 - 第四式: 使用Xpath提取網頁內容 >>>
Python 爬蟲十六式 - 第五式:BeautifulSoup,美味的湯 >>>
Python 爬蟲十六式 - 第六式:JQuery的假兄弟-pyquery >>>
Python 爬蟲十六式 - 第八式:例項解析-全書網 >>>

相關文章