爬蟲篇前面的某一章了,我們要爬取網站頁面源代碼的數據,要從中獲取到我們想要的數據,是不是感覺很費力,確實費力對吧?那么有沒有什么有利的工具來解決這個問題呢?那就是這一篇博文的主題——
正則表達式簡介
1.概念理解
正則表達式(Regular expressions 也稱為 REs,或 regexes 或 regex patterns)本質上是一個微小的且高度專業化的編程語言。正則表達式是一個特殊的字符序列,它能幫助你方便的檢查一個字符串是否與某種模式匹配。使用正則表達式,你需要指定一些規則來描述那些你希望匹配的字符串集合。這些字符串集合可能包含英語句子,e-mail 地址,任何你想要的東東。正則表達式模式被編譯成一系列的字節碼,然后由一個 C 語言寫的匹配引擎所執行(正因為正則表達式引擎是用 C 語言寫的,所以效率是極高)。對於高級的使用,你可能需要更關注匹配引擎是如何執行給定的 re,並通過一定的方式來編寫 re,以便產生一個可以運行得更快的字節碼。利用正則表達式,可以處理你 98% 的文本任務。
正則表達式對於Python來說並不是獨有的。它被嵌入到 Python 中,並通過 re 模塊提供給程序猿使用
提到正則表達式,那么必須得提到正則表達式的“幾元大將”,它們有一個統一的名字——元家軍,又名元字符
2.元字符
. ^ $ * + ? { } [ ] \ | ( )
如果沒有這幾個“將士”,那么正則表達式將變得和字符串的find()方法無二了。
那么這幾個“將士”什么來路呢?分別又有什么特技呢?
. :匹配任意字符,除了換行符。而當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符
^ :匹配字符串的開頭,脫字符
- 匹配輸入字符串的開始位置
- 如果設置了 re.MULTILINE 標志,^ 也匹配換行符之后的位置
$ :匹配字符串的末尾,如果設置了 re.MULTILINE 標志,$ 也匹配換行符之前的位置
* :匹配前面的子表達式零次或多次,等價於 {0,}
+ :匹配前面的子表達式一次或多次,等價於 {1,}
? :匹配前面的子表達式零次或一次,等價於 {0,1}
{M,N} :M 和 N 均為非負整數,其中 M <= N,表示前邊的 RE 匹配 M ~ N 次
- {M,} 表示至少匹配 M 次
- {,N} 等價於 {0,N}
- {N} 表示需要匹配 N 次
[...] :字符類,匹配所包含的任意一個字符
- 連字符 - 如果出現在字符串中間表示字符范圍描述;如果如果出現在首位則僅作為普通字符
- 特殊字符僅有反斜線 \ 保持特殊含義,用於轉義字符。其它特殊字符如 *、+、? 等均作為普通字符匹配
- 脫字符 ^ 如果出現在首位則表示匹配不包含其中的任意字符;如果 ^ 出現在字符串中間就僅作為普通字符匹配
\ :(下面還有詳解)
- 將一個普通字符變成特殊字符,例如 \d 表示匹配所有十進制數字
- 解除元字符的特殊功能,例如 \. 表示匹配點號本身
- 引用序號對應的子組所匹配的字符串
| :A | B,表示匹配正則表達式 A 或者 B
(...) :匹配圓括號中的正則表達式,或者指定一個子組的開始和結束位置。子組的內容可以在匹配之后被 \數字 再次引用
3.還有一些擴展出來的功能:
(?...):(? 開頭的表示為正則表達式的擴展語法(下邊這些是 Python 支持的所有擴展語法)
(?aiLmsux):
- (? 后可以緊跟着 'a','i','L','m','s','u','x' 中的一個或多個字符,只能在正則表達式的開頭使用
- 每一個字符對應一種匹配標志:re-A(只匹配 ASCII 字符),re-I(忽略大小寫),re-L(區域設置),re-M(多行模式), re-S(. 匹配任何符號),re-X(詳細表達式),包含這些字符將會影響整個正則表達式的規則
- 當你不想通過 re.compile() 設置正則表達式標志,這種方法就非常有用啦。注意,由於 (?x) 決定正則表達式如何被解析,所以它應該總是被放在最前邊(最多允許前邊有空白符)。如果 (?x) 的前邊是非空白字符,那么 (?x) 就發揮不了作用了。
(?:...):非捕獲組,即該子組匹配的字符串無法從后邊獲取
(?P<name>...):命名組,通過組的名字(name)即可訪問到子組匹配的字符串
(?P=name):反向引用一個命名組,它匹配指定命名組匹配的任何內容
(?#...):注釋,括號中的內容將被忽略
(?=...):前向肯定斷言。如果當前包含的正則表達式(這里以 ... 表示)在當前位置成功匹配,則代表成功,否則失敗。一旦該部分正則表達式被匹配引擎嘗試過,就不會繼續進行匹配了;剩下的模式在此斷言開始的地方繼續嘗試。
(?!...):前向否定斷言。這跟前向肯定斷言相反(不匹配則表示成功,匹配表示失敗)。
(?<=...):后向肯定斷言。跟前向肯定斷言一樣,只是方向相反。
(?<!...):后向否定斷言。跟前向肯定斷言一樣,只是方向相反。
(?(id/name)yes-pattern|no-pattern):如果子組的序號或名字存在的話,則嘗試 yes-pattern 匹配模式;否則嘗試 no-pattern 匹配模式,no-pattern 是可選的
比如(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一個匹配郵件格式的正則表達式,可以匹配 <user@fishc.com> 和 'user@fishc.com',但是不會匹配 '<user@fishc.com' 或 'user@fishc.com>'
\
正則表達式還支持大部分 Python 字符串的轉義符號:\a,\b,\f,\n,\r,\t,\u,\U,\v,\x,\\
- \b 通常用於匹配一個單詞邊界,只有在字符類中才表示“退格”
- \u 和 \U 只有在 Unicode 模式下才會被識別
- 八進制轉義(\數字)是有限制的,如果第一個數字是 0,或者如果有 3 個八進制數字,那么就被認為是八進制數;其他情況則被認為是子組引用;至於字符串,八進制轉義總是最多只能是 3 個數字的長度
\序號:
- 引用序號對應的子組所匹配的字符串,子組的序號從 1 開始計算
- 如果序號是以 0 開頭,或者 3 個數字的長度。那么不會被用於引用對應的子組,而是用於匹配八進制數字所表示的 ASCII 碼值對應的字符
\A:匹配輸入字符串的開始位置
\Z:匹配輸入字符串的結束位置
\b:匹配一個單詞邊界,單詞被定義為 Unidcode 的字母數字或下橫線字符
\B:匹配非單詞邊界,其實就是與 \b 相反
\d:
- 對於 Unicode(str 類型)模式:匹配任何一個數字,包括 [0-9] 和其他數字字符;如果開啟了 re.ASCII 標志,就只匹配 [0-9]
- 對於 8 位(bytes 類型)模式:匹配 [0-9] 中任何一個數字
\s:
- 對於 Unicode(str 類型)模式:匹配 Unicode 中的空白字符(包括 [ \t\n\r\f\v] 以及其他空白字符);如果開啟了 re.ASCII 標志,就只匹配 [ \t\n\r\f\v]
- 對於 8 位(bytes 類型)模式:匹配 ASCII 中定義的空白字符,即 [ \t\n\r\f\v]
\w:
- 對於 Unicode(str 類型)模式:匹配任何 Unicode 的單詞字符,基本上所有語言的字符都可以匹配,當然也包括數字和下橫線;如果開啟了 re.ASCII 標志,就只匹配 [a-zA-Z0-9_]
- 對於 8 位(bytes 類型)模式:匹配 ASCII 中定義的字母數字,即 [a-zA-Z0-9_]
