題記
本文介紹了Python對于正則表達式的支持,包括正則表達式基礎以及Python正則表達式標準庫的完整介紹及使用示例。
正則表達式在很多的應用中都有使用到,特別是在網絡爬蟲中格式化html后取出自己需要的屬性,在字符串的匹配和查找中也有很多的應用。
本文主要使用python對正則表達式進行說明,并配合合適的代碼。
如何匹配手機號碼
正則表達式的規則,一開始看的時候,會感覺規則太多太亂,毫無規律可尋,看完了幾個例子以后,慢慢的發現一些常用的表達式以后,寫起后面的規則就容易得多了。
這里以如何匹配手機電話號碼為例子
最簡單的手機規律為11個數字,正則表達式為:
\d{11}
這樣我們就認為凡事字符串中有11位數字就認為是手機號碼,但是現實中還有另外一些規則,12345678912這也是11個數字,但是我們現在并不會認為他是手機號碼,所以進一步的把規則寫細了。
我們還可以進一步的細分為,13x開頭,14x開頭,17(13678)開頭,18x開頭,后面再帶8位的數字,還有另一種情況是170的情況,其中第四位為[0589]中的一個數,再帶7位數字。
表達式可以寫為:
(13\d|14[57]|15[^4,\D]|17[13678]|18\d)\d{8}|170[0589]\d{7}
正則表達式語法
我們剛才用到的\d 在正則表達式中,代表著數字的意思,還可以用[0-9]來表示一個數字。語法比較多,但是常用的并不是很多,圖中表示的是常見的語法。
字符串匹配:
| 語法 | 含義 |
| -------- | :-----: |
| \d | 數字 |
| \D | 非數字 |
| \s | 空白符 |
| \S | 非空白符 |
| \w | 單詞字符 |
| \W | 非單詞字符 |
數量匹配:
| 語法 | 含義 |
| -------- | :-----: |
| * | 匹配前面字符0次到無限次 |
| + | 匹配前面字符1次到無限次 |
| ? | 匹配前面字符0到1次 |
|{m} | 匹配前面字符m次 |
| {m,n} | 匹配前面字符m到n次 |
匹配邊界:
| 語法 | 含義 |
| -------- | :-----: |
| ^ | 匹配字符串開頭 |
| $ | 匹配字符串末尾 |
圖中的表達式都有專門的例子介紹,可以大概的看看,需要用到的時候在專門來進行查詢。
python中的re模塊
在python中,有專門的模塊來負責正則表達式,就是re模塊。
字符串是否匹配規則
比如在用戶注冊里,我們要求用戶輸入的手機號碼,符合手機號碼的規律,可以用正則表達式來限制。
查看字符串中
是否有符合要求的字符串,還是以剛才的手機號碼為例:
import re
str = '15259340987'
# 將正則表達式編譯成Pattern對象
pattern = re.compile('152\d{8}')
# 使用Pattern匹配文本,獲得匹配結果,無法匹配時將返回None
match = pattern.match(str)
if match:
# 使用Match獲得分組信息
print match.group()
str = '15259340987'
# 將正則表達式編譯成Pattern對象
pattern = re.compile('152\d{8}')
# 使用Pattern匹配文本,獲得匹配結果,無法匹配時將返回None
match = pattern.match(str)
if match:
# 使用Match獲得分組信息
print match.group()
這里可以看出正則表達式,用的是
re.compile('152\d{8}')
這個表達式比
(13\d|14[57]|15[^4,\D]|17[13678]|18\d)\d{8}|170[0589]\d{7}
是嚴格非常多的,他只匹配,152開頭的手機號碼,當然表達式可以根據你自己的需要來選擇,這里只是給一個實例。
找出所有符合規則的字符串
在網頁爬蟲中,我們需要找出網頁的說有鏈接,用正則匹配就非常容易做到,查看網頁源代碼中的html,帶有網頁鏈接的代碼為
href="http://tech.sina.com.cn/t/2017-08-17/doc-ifykcppx8531845.shtml"
正則表達式可以寫成:
href="(.*?)"
python代碼為:
import re
str = ''
# 匹配
links = re.findall('href="(.*?)"', str)
for link in links:
print link
# 輸出為:
# http://tech.sina.com.cn/t/2017-08-17/doc-ifykcppx8531845.shtml
str = ''
# 匹配
links = re.findall('href="(.*?)"', str)
for link in links:
print link
# 輸出為:
# http://tech.sina.com.cn/t/2017-08-17/doc-ifykcppx8531845.shtml
找出了所有需要的鏈接。
re模塊中重要的接口
- re.compile(pattern, flags=0)
這個方法是Pattern類的工廠方法,用于將字符串形式的正則表達式編譯為Pattern對象。 第二個參數flag是匹配模式,取值可以使用按位或運算符'|'表示同時生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile('pattern', re.I | re.M)與re.compile('(?im)pattern')是等價的。
語句
prog = re.compile(pattern)
result = prog.match(string)
和
result = re.match(pattern, string)
等價,第二種寫法較為方便。
- re.search(pattern, string, flags=0)
這個方法用于查找字符串中可以匹配成功的子串。從string的pos下標處起嘗試匹配pattern,如果pattern結束時仍可匹配,則返回一個Match對象;若無法匹配,則將pos加1后重新嘗試匹配;直到pos=endpos時仍無法匹配則返回None。
pos和endpos的默認值分別為0和len(string));re.search()無法指定這兩個參數,參數flags用于編譯pattern時指定匹配模式。
- re.match(pattern, string, flags=0)
這個方法將從string的pos下標處起嘗試匹配pattern;如果pattern結束時仍可匹配,則返回一個Match對象;如果匹配過程中pattern無法匹配,或者匹配未結束就已到達endpos,則返回None。
pos和endpos的默認值分別為0和len(string);re.match()無法指定這兩個參數,參數flags用于編譯pattern時指定匹配模式。
注意:這個方法并不是完全匹配。當pattern結束時若string還有剩余字符,仍然視為成功。想要完全匹配,可以在表達式末尾加上邊界匹配符'$'。
- re.split(pattern, string, maxsplit=0, flags=0)
按照能夠匹配的子串將string分割后返回列表。maxsplit用于指定最大分割次數,不指定將全部分割。
- re.findall(pattern, string, flags=0)
搜索string,以列表形式返回全部能匹配的子串。
- re.sub(pattern, repl, string, count=0, flags=0)
使用repl替換string中每一個匹配的子串后返回替換后的字符串。
當repl是一個字符串時,可以使用\id或\g<id>、\g<name>引用分組,但不能使用編號0。
當repl是一個方法時,這個方法應當只接受一個參數(Match對象),并返回一個字符串用于替換(返回的字符串中不能再引用分組)。
count用于指定最多替換次數,不指定時全部替換。
常用的正則表達式語句
- 匹配郵箱:\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
- 匹配中文:[\u4e00-\u9fa5]
- 匹配IP(IPV4):(\d+)\.(\d+)\.(\d+)\.(\d+)
- 匹配身份證:\d{15}|\d{17}[0-9Xx]
- 匹配手機號:(13\d|14[57]|15[^4,\D]|17[13678]|18\d)\d{8}|170[0589]\d{7}
正則表達式工具
正則表達式語法比較復雜,開始沒有經驗的話,調試起來比較麻煩,現在網上有很多的正則表達式工具,能幫助我們快速的進行試驗。有客戶端的工具也有web工具,用起來都較為方便。
用的較多的是RegexBuddy這一款工具,如圖,他可以自動的生成各種語言版本的正則表達式的例子:
如下

更多入門教程可以參考:http://www.bugingcode.com/python_start/