[TOC]
# re庫正則表達式的基礎使用
> 正則表達式的好處就是可以通過簡短表達式精準表達需要匹配內容,然后在文本數據中快速匹配提取到需要的文本內容。
正則表達式可以很簡短,也可以很復雜,可能對于同一個結果,不同人寫出來的表達式也是千差萬別。
為了能夠寫出優雅的正則表達式,我們首先了解一下它的語法信息,在不斷練習實踐,才能達到了熟練使用正則表達式的效果。
## 正則表達式語法
> 為了方便理解記憶,下面將正則表達式進行了歸類整理。
### 元字符含義
| 元字符 | 含義 |
| :----- | :-------------------- |
| . | (點) 在默認模式,匹配除了換行的任意字符。如果指定了標簽 DOTALL ,它將匹配包括換行符的任意字符。 |
| \\ | 轉義特殊字符(允許你匹配 '*', '?', 或者此類其他),或者表示一個特殊序列; 為了防止`反斜杠災難`,推薦無論多簡單的表達式都要使用 r(raw) 原生字符串來表達,例如: r"\\w.*" |
| [] | 用于表示一個字符集合。比如 [amk] 匹配 'a', 'm', 或者 'k'。 可以表示字符范圍,通過用 '-' 將兩個字符連起來。 比如 [a-z] 將匹配任何小寫ASCII字符. 特殊字符在集合中,失去它的特殊含義。比如 [(+*)] 只會匹配這幾個文法字符 '(', '+', '*', or ')'。 字符類如 \w 或者 \S (如下定義) 在集合內可以接受,它們可以匹配的字符由 ASCII 或者 LOCALE 模式決定。 '^'字符放在開始位置表示取反操作,例如 [^5] 將匹配所有字符,除了 '5',但是 [5^] 將匹配 '5' 或 '^'。 在集合內要匹配一個字符 ']',有兩種方法,要么就在它之前加上反斜杠,要么就把它放到集合首位。比如, [()[\]{}] 和 []()[{}] 都可以匹配括號。 |
| \| | A\|B, A 和 B 可以是任意正則表達式,創建一個正則表達式,匹配 A 或者 B. 任意個正則表達式可以用 '\|' 連接。它也可以在組合(見下列)內使用。掃描目標字符串時, '\|' 分隔開的正則樣式從左到右進行匹配。當一個樣式完全匹配時,這個分支就被接受。意思就是,一旦 A 匹配成功, B 就不再進行匹配,即便它能產生一個更好的匹配。或者說,'\|' 操作符絕不貪婪。 如果要匹配 '\|' 字符,使用 \\\|, 或者把它包含在字符集里,比如 [\|]. |
### 重復匹配
| 元字符 | 含義 |
| :---- | :------------- |
| * | 對它前面的正則式匹配0到任意次重復, 盡量多的匹配字符串。 ab* 會匹配 'a', 'ab', 或者 'a'``后面跟隨任意個 ``'b'。 |
| + | 對它前面的正則式匹配1到任意次重復。 ab+ 會匹配 'a' 后面跟隨1個以上到任意個 'b',它不會匹配 'a'。 |
| ? | 對它前面的正則式匹配0到1次重復。 ab? 會匹配 'a' 或者 'ab'。 |
| *?, +?, ?? | **非貪婪模式匹配**,字符串'abc'在使用正則式 <.*?>時 將會僅僅匹配 '<a>'。 |
| {m} | 對其之前的正則式指定匹配 m 個重復;少于 m 的話就會導致匹配失敗。比如, a{6} 將匹配6個 'a' , 但是不能是5個。 |
| {m,n} | 對正則式進行 m 到 n 次匹配,在 m 和 n 之間取盡量多。 比如,a{3,5} 將匹配 3 到 5個 'a'。忽略 m 意為指定下界為0,忽略 n 指定上界為無限次。 比如 a{4,}b 將匹配 'aaaab' 或者1000個 'a' 尾隨一個 'b',但不能匹配 'aaab'。逗號不能省略,否則無法辨別修飾符應該忽略哪個邊界。 |
| {m,n}? | 前一個修飾符的**非貪婪模式**,只匹配盡量少的字符次數。比如,對于 'aaaaaa', a{3,5} 匹配 5個 'a' ,而 a{3,5}? 只匹配3個 'a'。 |
### 邊界匹配
| 元字符 | 含義 |模式示例 |匹配成功 | 匹配失敗 |
| :------ | :------------- |:--------- |:--------- |:-------- |
| ^ | 匹配字符串開始,并且在 MULTILINE 模式也匹配換行后的首個符號。 | ^ABC | ABC | abcABC |
| $ | 匹配字符串末尾,在 MULTILINE 模式匹配換行符的前一個字符。 | ABC\$ | abcABC | abcdABCD|
| \A | 只匹配字符串開始。 | ^ABC | ABC | abcABC |
| \Z | 只匹配字符串末尾。 | ABC$ | xABC | xABCD|
| \b | 單詞邊界匹配,匹配空字符串,但只在單詞開始或結尾的位置。 | r\bfoo\b | 'foo','foo.' | 'abcfooxyz', 'foo3' |
| \B | 匹配空字符串,但不能在詞的開頭或者結尾。 與\b語義相反。 | r'py\B' | 'python','py3' | 'py','py.' |
| \d | Unicode下匹配數字0-9和其他數字符號,ASCII下匹配0-9的數字。 | r'A\dC' | 'A2C' | 'ABC' |
| \D | 匹配任何非十進制數字的字符。就是 \d 取非。 | r'A\DC' | 'ABC' | 'A2C' |
| \s | 匹配ASCII中的空白字符,就是 [ \t\n\r\f\v] | r'bob\sis' | 'bob is ...' | 'bobisaboy' |
| \S | 匹配任何非空白字符。就是 \s 取非。如果設置了 ASCII 標志,就相當于 [^ \t\n\r\f\v] 。 | r'(\S+)\s+(\S+)' | 'hello world' | 'helloworld' |
| \w | 匹配Unicode詞語的字符,包含了可以構成詞語的絕大部分字符,也包括數字和下劃線。如果設置了 ASCII 標志,就只匹配 [a-zA-Z0-9_] 。 匹配ASCII字符中的數字和字母和下劃線,就是 [a-zA-Z0-9_] 。如果設置了 LOCALE 標記,就匹配當前語言區域的數字和字母和下劃線。 | r'\b\w+\b' | 'adkfa' | '[]' ,'&' |
| \W | 匹配非單詞字符的字符。這與 \w 正相反。如果使用了 ASCII 旗標,這就等價于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗標,則會匹配當前區域中既非字母數字也非下劃線的字符。 | r'name\Wvalue' | 'name=value' | 'name_value'|
### 分組
| 元字符 | 含義 |模式示例 |匹配成功 | 匹配失敗 |
| :------ | :------------- |:--------- |:--------- |:-------- |
| (...) | (組合),匹配括號內的任意正則表達式,并標識出組合的開始和結尾。匹配完成后,組合的內容可以被獲取,并可以在之后用 \\number 轉義序列進行再次匹配,之后進行詳細說明。要匹配字符 '(' 或者 ')', 用 \\( 或 \\), 或者把它們包含在字符集合里: [(], [)]. | r'1(abc\|xyz)2' | '1abc2','1xyz2' | '1abcxyz2' |
|(?P\<name\>) | (命名組合)類似正則組合,但是匹配到的子串組在外部是通過定義的 name 來獲取的。 | (?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(無引號)|
| (?P=name) | 引用別名為name的分組字符串 |(?P\<quote>['"]).*?(?P=quote) |"xyz"|abc(無引號)|
| \\number | 引用編號為<number>的分組字符串 | (['"]).*?\1 |"xyz"|abc(無引號)|
### 特殊組合(使用()表達式但是卻不作為分組獲取)
| 元字符 | 含義 |模式示例 |匹配成功 | 匹配失敗 |
| :------ | :------------- |:--------- |:--------- |:-------- |
|(?:…) |正則括號的非捕獲版本。 匹配在括號內的任何正則表達式,但該分組所匹配的子字符串 不能 在執行匹配后被`獲取`或是之后在模式中被`引用`。這是與(...) 分組之間的區別。例如這樣使用是錯誤的r'(?:abc)\\1'| r'(?i)(http://.*?(?:jpg|png|jpeg))'| 'http:xxx.xxx/1001.jpg' | 'http:xxx.xxx/1002.svg' |
| (?aiLmsux)|( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一個或多個) 這個組合匹配一個空字符串;這些字符對正則表達式設置以下標記 re.A (只匹配ASCII字符), re.I (忽略大小寫), re.L (語言依賴), re.M (多行模式), re.S (點dot匹配全部字符), re.U (Unicode匹配), and re.X (冗長模式)。 (這些標記在 模塊內容 中描述) 如果你想將這些標記包含在正則表達式中,這個方法就很有用,免去了在 re.compile() 中傳遞 flag 參數。標記應該在表達式字符串首位表示。 |r'(?i)abc' |Abc | axbc |
|(?#…) | 注釋;里面的內容會被忽略。| name(?#this is a comment)=123 | name=123 | namexxxx |
|(?=…) |匹配 … 的內容,但是并不消費樣式的內容。這個叫做 lookahead assertion。 | Isaac (?=Asimov)|IsaacAsimov | Isaac|
|(?!…) |匹配 … 不符合的情況。這個叫 negative lookahead assertion (前視取反)。 | Isaac (?!Asimov)| Isaac| IsaacAsimov|
|(?\<=…) |匹配字符串的當前位置,它的前面匹配 … 的內容到當前位置。這叫:dfn:positive lookbehind assertion (正向后視斷定)。**注意以 positive lookbehind assertions 開始的樣式,如 (?<=abc)def ,并不是從 a 開始搜索,而是從 d 往回看的。你可能更加愿意使用 search() 函數,而不是 match() 函數**,使用match()函數會出現匹配失敗的情況的。 |r'(?<=-)\w+' |abc-def | xyzdef |
|(?<!…) | 匹配當前位置之前不是 ... 的樣式。這個叫 negative lookbehind assertion (后視斷定取非)。|r'(?<!-)\w+' | xyzdef | abc-def|
## 正則函數使用
| 函數定義 | 含義 |
| :------ | :------------- |
|re.search(pattern, string, flags=0) | 掃描整個 字符串 找到匹配樣式的第一個位置,并返回一個相應的 匹配對象。如果沒有匹配,就返回一個 None ; 注意這和找到一個零長度匹配是不同的。|
|re.match(pattern, string, flags=0)|如果 string 開始的0或者多個字符匹配到了正則表達式樣式,就返回一個相應的 匹配對象 。 如果沒有匹配,就返回 None ;注意它跟零長度匹配是不同的。注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的開始位置,而不匹配每行開始。如果你想定位 string 的任何位置,使用 search() 來替代。|
|re.fullmatch(pattern, string, flags=0)|如果整個 string 匹配到正則表達式樣式,就返回一個相應的 匹配對象 。 否則就返回一個 None ;注意這跟零長度匹配是不同的。|
|re.split(pattern, string, maxsplit=0, flags=0)|用 pattern 分開 string 。 如果在 pattern 中捕獲到括號,那么所有的組里的文字也會包含在列表里。如果 maxsplit 非零, 最多進行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一個元素。|
|re.findall(pattern, string, flags=0)|對 string 返回一個不重復的 pattern 的匹配列表, string 從左到右進行掃描,匹配按找到的順序返回。如果樣式里存在一到多個組,就返回一個組合列表;就是一個元組的列表(如果樣式里有超過一個組合的話)。空匹配也會包含在結果里。|
|re.finditer(pattern, string, flags=0)|pattern 在 string 里所有的非重復匹配,返回為一個迭代器 iterator 保存了 匹配對象 。 string 從左到右掃描,匹配按順序排列。空匹配也包含在結果里。|
|re.sub(pattern, repl, string, count=0, flags=0) | 返回通過使用 repl 替換在 string 最左邊非重疊出現的 pattern 而獲得的字符串。 如果樣式沒有找到,則不加改變地返回 string。 repl 可以是字符串或函數;如為字符串,則其中任何反斜杠轉義序列都會被處理。|
|re.subn(pattern, repl, string, count=0, flags=0) | 行為與 sub() 相同,但是返回一個元組 (字符串, 替換次數).|
|re.escape(pattern) |轉義 pattern 中的特殊字符。如果你想對任意可能包含正則表達式元字符的文本字符串進行匹配,它就是有用的。 |
|re.purge() | 清除正則表達式的緩存。|
### match() 與 search() 函數比較
Python 提供了兩種不同的操作:基于 re.match() 檢查字符串開頭,或者 re.search() 檢查字符串的任意位置(默認Perl中的行為)。
例如:
```Python
>>>
>>> re.match("c", "abcdef") # No match
>>> re.search("c", "abcdef") # Match
<re.Match object; span=(2, 3), match='c'>
```
在 search() 中,可以用 '^' 作為開始來限制匹配到字符串的首位:
```Python
>>>
>>> re.match("c", "abcdef") # No match
>>> re.search("^c", "abcdef") # No match
>>> re.search("^a", "abcdef") # Match
<re.Match object; span=(0, 1), match='a'>
```
**注意** `MULTILINE` 多行模式中函數 match() 只匹配字符串的開始,但使用 search() 和以 '^' 開始的正則表達式會匹配每行的開始
```Python
>>>
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<re.Match object; span=(4, 5), match='X'>
```
## 匹配對象處理函數
| 函數定義 | 含義 |
| :-------- | :------------- |
| Match.expand(template) | 對 template 進行反斜杠轉義替換并且返回,就像 sub() 方法中一樣。轉義如同 \n 被轉換成合適的字符,數字引用(\1, \2)和命名組合(\g<1>, \g<name>) 替換為相應組合的內容。|
|Match.group([group1, ...])|返回一個或者多個匹配的子組。如果只有一個參數,結果就是一個字符串,如果有多個參數,結果就是一個元組(每個參數對應一個項),如果沒有參數,組1默認到0(整個匹配都被返回)。|
|Match.groups(default=None)|返回一個元組,包含所有匹配的子組,在樣式中出現的從1到任意多的組合。 default 參數用于不參與匹配的情況,默認為 None。|
```Python
>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0) # The entire match
'Isaac Newton'
>>> m.group(1) # The first parenthesized subgroup.
'Isaac'
>>> m.group(2) # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2) # Multiple arguments give us a tuple.
('Isaac', 'Newton')
>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups() # Second group defaults to None.
('24', None)
>>> m.groups('0') # Now, the second group defaults to '0'.
('24', '0')
```
- 課程大綱
- 入門篇
- 爬蟲是什么
- 為什么要學習爬蟲
- 爬蟲的基本原理
- TCP/IP協議族的基本知識
- HTTP協議基礎知識
- HTML基礎知識
- HTML_DOM基礎知識
- urllib3庫的基本使用
- requests庫的基本使用
- Web頁面數據解析處理方法
- re庫正則表達式的基礎使用
- CSS選擇器參考手冊
- XPath快速了解
- 實戰練習:百度貼吧熱議榜
- 進階篇
- 服務端渲染(CSR)頁面抓取方法
- 客戶端渲染(CSR)頁面抓取方法
- Selenium庫的基本使用
- Selenium庫的高級使用
- Selenium調用JavaScript方法
- Selenium庫的遠程WebDriver
- APP移動端數據抓取基礎知識
- HTTP協議代理抓包分析方法
- Appium測試Android應用基礎環境準備
- Appium爬蟲編寫實戰學習
- Appium的元素相關的方法
- Appium的Device相關操作方法
- Appium的交互操作方法
- 代理池的使用與搭建
- Cookies池的搭建與用法
- 數據持久化-數據庫的基礎操作方法(mysql/redis/mongodb)
- 執行JS之execjs庫使用
- 高級篇
- Scrapy的基本知識
- Scrapy的Spider詳細介紹
- Scrapy的Selector選擇器使用方法
- Scrapy的Item使用方法
- Scrapy的ItemPipeline使用方法
- Scrapy的Shell調試方法
- Scrapy的Proxy設置方法
- Scrapy的Referer填充策略
- Scrapy的服務端部署方法
- Scrapy的分布式爬蟲部署方法
- Headless瀏覽器-pyppeteer基礎知識
- Headless瀏覽器-pyppeteer常用的設置方法
- Headless瀏覽器-反爬應對辦法
- 爬蟲設置技巧-UserAgent設置
- 反爬策略之驗證碼處理方法
- 反爬識別碼之點擊文字圖片的自動識別方法
- 反爬字體處理方法總結
- 防止反爬蟲的設置技巧總結
- 實戰篇
- AJAX接口-CSDN技術博客文章標題爬取
- AJAX接口-拉購網職位搜索爬蟲
- 執行JS示例方法一之動漫圖片地址獲取方法
- JS執行方法示例二完整mangabz漫畫爬蟲示例
- 應用實踐-SOCKS代理池爬蟲
- 落霞小說爬蟲自動制作epub電子書
- 一種簡單的適用于分布式模式知乎用戶信息爬蟲實現示例
- 法律安全說明