正則表達式(re 模塊)
一、re 模塊的使用過程
# 導入 re 模塊 import re # 使用 match 方法進行匹配操作 # re.match() 能夠匹配出以 xxx 開頭的字符串 result = re.match(r'正則表達式', '被匹配的字符串') if result: # 如果上一步匹配到數(shù)據(jù)的話,可以使用 group 方法來提取數(shù)據(jù) print(result.group()) else: print('匹配失敗')
- Python 中字符串前面加上 r 表示原生字符串。與大多數(shù)編程語言相同,正則表達式里使用 “\” 作為轉義字符,這就可能造成反斜杠困擾。
- Python 里的原生字符串很好地解決了這個問題,同時寫出來的表達式也更直觀。注意 r 只服務于 “\” ,不對其他進行轉義。
二、正則表達式的字符匹配
1. 匹配開頭結尾
| 字符 | 介紹 |
|---|---|
^ |
匹配字符串的開頭 |
$ |
匹配字符串的末尾 |
2. 匹配單個字符

- \ 是轉義特殊字符,\n 代表換行、\r 代表回車、\f 代表換頁、\t 代表 Tab 鍵
- 通過用 ‘-’ 將兩個字符連起來可以表示字符范圍,比如:
- [a-z] 將匹配任何小寫 ASCII 字符, [0-5][0-9] 將匹配從 00 到 59 的兩位數(shù)字,[0-9A-Fa-f] 將匹配任何十六進制數(shù)位。
- 如果 - 進行了轉義 (比如 [a\-z])或者它的位置在首位或末尾(如 [-a] 或 [a-]),那么它就只表示普通字符 ‘-’
- 除反斜杠外的特殊字符在 [ ] 中會失去其特殊含義,例如:[(+*)] 將匹配字符為 ( + * 或 ) 中的任何一個
3. 匹配多個字符

- ab* 會匹配 ‘a(chǎn)’,‘a(chǎn)b’,或者 ‘a(chǎn)’ 后面跟隨任意個 ‘b’
- ab+ 會匹配 ‘a(chǎn)’ 后面跟隨 1 個以上到任意個 ‘b’,它不會匹配 ‘a(chǎn)’
- ab? 會匹配 ‘a(chǎn)’ 或者 ‘a(chǎn)b’
- a{6} 將匹配 6 個 ‘a(chǎn)’ , 少于 6 個的話就會導致匹配失敗
- a{3,5} 將匹配 3 到 5 個 ‘a(chǎn)’
4. 匹配分組

5. Python 代碼示例
- 匹配出 126、163、qq 的郵箱地址,且 @ 符號之前有 4 到 20 位數(shù)字、大寫或小寫字母和下劃線的組合。
import re email_list = ["Alice27@163.com", "Sam_1122@gmail.com", ".Tom_12@qq.com", "Bob_1988@qq.com.com", "Elowen@126.com", "Ice@qq.com", "nicetomeetyou@qq.com"] for email in email_list: ret = re.match(r"\w{4,20}@(163|126|qq)\.com$", email) if ret: print("%s 是符合規(guī)定的郵件地址 , 匹配后的結果是 : %s" % (email, ret.group())) else: print("%s 不符合要求" % email)
結果展示:
Alice27@163.com 是符合規(guī)定的郵件地址 , 匹配后的結果是 : Alice27@163.com Sam_1122@gmail.com 不符合要求 .Tom_12@qq.com 不符合要求 Bob_1988@qq.com.com 不符合要求 Elowen@126.com 是符合規(guī)定的郵件地址 , 匹配后的結果是 : Elowen@126.com Ice@qq.com 不符合要求 nicetomeetyou@qq.com 是符合規(guī)定的郵件地址 , 匹配后的結果是 : nicetomeetyou@qq.com
- 匹配 11 位不是以 4、7 結尾的手機號碼:re.match(r"1\d{9}[0-35-68-9]$", tel)
- 提取區(qū)號和電話號碼:ret = re.match(r"([^-]+)-(\d+)","010-12345678") ,此時 ret.group(1) = ‘010’ ,ret.group(2) = ‘12345678’ ,ret.group(0) 等價于 ret.group() 等于 ‘010-12345678’
- 匹配標簽,例如:匹配 <html><h1>hello</h1></html> 并提取出 hello
import re texts = ['<html><h1>hello</h1></html>', '<html><h1>world</h1></html1html>', '<html><h1>hello</h2></html>'] def match(): for text in texts: ret = re.match(r'<([a-zA-Z]*)><([a-zA-Z0-9]*)>(\w*)</\2></\1>', text) if ret: print(f'匹配成功,標簽為 {ret.group()},信息為 {ret.group(3)}') else: print(f'{text} 標簽匹配失敗') if __name__ == '__main__': match()
結果展示:
匹配成功,標簽為 <html><h1>hello</h1></html>,信息為 hello <html><h1>world</h1></html1html> 標簽匹配失敗 <html><h1>hello</h2></html> 標簽匹配失敗
用 (?P<name>) 和 (?P=name) 改進上述示例:
re.match(r'<(?P<name1>[a-zA-Z]*)><(?P<name2>[a-zA-Z0-9]*)>(\w*)</(?P=name2)></(?P=name1)>', text)
注意:字母 P 要大寫
三、re 模塊的函數(shù)
1. 函數(shù)一覽表

result = re.match(pattern, string) 等價于 prog = re.compile(pattern) 和 result = prog.match(string) 。
re.split 函數(shù)中如果 maxsplit 非零,則最多進行 maxsplit 次分隔,剩下的字符全部返回到列表的最后一個元素。
2. Python 代碼示例
1)search 與 finditer
需求:匹配出文章閱讀的次數(shù)和點贊的次數(shù)。
import re def find_second_match(pattern, text): matches = re.finditer(pattern, text) try: next(matches) # 跳過第一個匹配項 second_match = next(matches) # 獲取第二個匹配項 return second_match.group() except StopIteration: return None if __name__ == '__main__': p = r"\d+" t = "閱讀次數(shù)為 9999 , 點贊次數(shù)為 19999" ret = re.search(p, t) print(f'閱讀次數(shù)為 {ret.group()} , 點贊次數(shù)為 {find_second_match(p, t)}')
結果展示:
閱讀次數(shù)為 9999 , 點贊次數(shù)為 19999
2)findall
- 需求:統(tǒng)計出相應文章閱讀、點贊和收藏的次數(shù)。
import re ret = re.findall(r"\d+", "read = 9999, thumbs up = 7890, collection = 12345") print(f'閱讀次數(shù) {ret[0]} ,點贊次數(shù) {ret[1]} ,收藏次數(shù) {ret[2]}')
結果展示:
閱讀次數(shù) 9999 ,點贊次數(shù) 7890 ,收藏次數(shù) 12345
【拓展】:分組() 內(nèi)加入 ?: 可以避免只返回分組內(nèi)的內(nèi)容。
- 需求:提取出字符串里的日期和時間 。
import re if __name__ == '__main__': s = 'hello world, now is 2020/7/20 18:48, 現(xiàn)在是 2020年7月20日18時48分。' ret_s = re.sub(r'年|月', r'/', s) ret_s = re.sub(r'日|分', r' ', ret_s) ret_s = re.sub(r'時', r':', ret_s) # hello world, now is 2020/7/20 18:48, 現(xiàn)在是 2020/7/20 18:48 。 print(ret_s) # findall com1 = re.compile(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]') ret1 = com1.findall(ret_s) print(ret1[0]) # 18 # 加 ?: com2 = re.compile(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(?:0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]') ret2 = com2.findall(ret_s) print(ret2[0]) # 2020/7/20 18:48 # search ret3 = re.search(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]', ret_s) print(ret3.group()) # 2020/7/20 18:48
3)sub
將匹配到的數(shù)據(jù)進行替換。
- 需求:將匹配到的閱讀次數(shù)加 1 。
import re def add(temp): str_num = temp.group() num = int(str_num) + 1 return str(num) if __name__ == '__main__': ret = re.sub(r"\d+", '998', "thumbs up = 997") print(ret) ret = re.sub(r"\d+", add, "thumbs up = 997") print(ret) ret = re.sub(r"\d+", lambda x: str(int(x.group()) + 1), "thumbs up = 997") print(ret) print('-' * 30) # count 替換次數(shù) text = "apple apple apple apple" pattern = r"apple" replacement = "orange" new_text = re.sub(pattern, replacement, text, count=2) print(new_text)
結果展示:
thumbs up = 998 thumbs up = 998 thumbs up = 998 ------------------------------ orange orange apple apple
- 需求:刪除字符串中所有的 HTML 標簽和
實體,只留下純文本內(nèi)容。
import re if __name__ == '__main__': text = ('<div>' + '\n' + '<p>崗位職責:</p>' + '\n' + '<p>完成推薦算法、數(shù)據(jù)統(tǒng)計、接口、后臺等服務器端相關工作</p>' + '\n' + '<p><br></p>' + '\n' + '<p>必備要求:</p>' + '\n' + '<p>良好的自我驅動力和職業(yè)素養(yǎng),工作積極主動、結果導向</p>' + '\n' + '<p> <br></p>' + '\n' + '<p>技術要求:</p>' + '\n' + '<p>1、一年以上 Python 開發(fā)經(jīng)驗,掌握面向對象分析和設計,了解設計模式</p>' + '\n' + '<p>2、掌握 HTTP 協(xié)議,熟悉 MVC、MVVM 等概念以及相關 WEB 開發(fā)框架</p>' + '\n' + '<p>3、掌握關系數(shù)據(jù)庫開發(fā)設計,掌握 SQL,熟練使用 MySQL/PostgreSQL 中的一種<br></p>' + '\n' + '<p>4、掌握 NoSQL、MQ,熟練使用對應技術解決方案</p>' + '\n' + '<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>' + '\n' + '<p> <br></p>' + '\n' + '<p>加分項:</p>' + '\n' + '<p>大數(shù)據(jù),數(shù)理統(tǒng)計,機器學習,sklearn,高性能,大并發(fā)。</p>' + '\n' + '</div>') # print(text) sub_result = re.sub(r"<[^>]*>| ", "", text) print(sub_result)
結果展示:
崗位職責: 完成推薦算法、數(shù)據(jù)統(tǒng)計、接口、后臺等服務器端相關工作 必備要求: 良好的自我驅動力和職業(yè)素養(yǎng),工作積極主動、結果導向 技術要求: 1、一年以上 Python 開發(fā)經(jīng)驗,掌握面向對象分析和設計,了解設計模式 2、掌握 HTTP 協(xié)議,熟悉 MVC、MVVM 等概念以及相關 WEB 開發(fā)框架 3、掌握關系數(shù)據(jù)庫開發(fā)設計,掌握 SQL,熟練使用 MySQL/PostgreSQL 中的一種 4、掌握 NoSQL、MQ,熟練使用對應技術解決方案 5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js 加分項: 大數(shù)據(jù),數(shù)理統(tǒng)計,機器學習,sklearn,高性能,大并發(fā)。
解析正則表達式:r"<[^>]*>| "
- <[^>]*> :匹配一對尖括號 < > 及其內(nèi)部內(nèi)容,且內(nèi)容不包含 > 符號,表示匹配 HTML 標簽,比如 <div>, <a href=“…”> 等。
- | :表示 “或” 操作符。
- :匹配 HTML 的不間斷空格實體 。
- 替換字符串是 “” ,即將匹配的內(nèi)容替換為空字符串(刪除)。
4)split
根據(jù)匹配進行切割字符串,并返回一個列表。需求:切割字符串 “info:xiaoZhang 33 shandong” 。
import re ret = re.split(r":| ","info:xiaoZhang 33 shandong") print(ret)
結果展示:
['info', 'xiaoZhang', '33', 'shandong']
四、貪婪與非貪婪
Python 里數(shù)量詞默認是貪婪的,即總是嘗試匹配盡可能多的字符,而非貪婪則相反,總是嘗試匹配盡可能少的字符。
可以在 * , ? , + , {m,n} 后面加上非貪婪操作符 ? ,該操作符要求正則匹配的字符越少越好,因而可以將貪婪轉變?yōu)榉秦澙贰?/span>
Python 代碼示例:
import re if __name__ == '__main__': s = "This is a number 234-235-22-423" # 貪婪 print(re.match(r".+(\d+-\d+-\d+-\d+)", s).group(1)) print(re.match(r"aa(\d+)", "aa2343ddd").group(1)) print(re.match(r"aa(\d+)ddd", "aa2343ddd").group(1)) print('-' * 30) # 非貪婪 print(re.match(r".+?(\d+-\d+-\d+-\d+)", s).group(1)) print(re.match(r"aa(\d+?)", "aa2343ddd").group(1)) print(re.match(r"aa(\d+?)ddd", "aa2343ddd").group(1))
結果展示:
4-235-22-423 2343 2343 ------------------------------ 234-235-22-423 2 2343
五、re 模塊的可選標志
Python 代碼示例:
import re if __name__ == '__main__': s1 = 'hello\nworld' ret1 = re.match(r'hello.W', s1, re.S | re.I) if ret1: print(ret1.group()) # hello w else: print('no match') print('-' * 15) s2 = 'hello你好world' ret2 = re.match(r'hello\w*', s2, re.A) if ret2: print(ret2.group()) # hello else: print('no match')

浙公網(wǎng)安備 33010602011771號