python re 匹配多行_Python正则表达式,看这一篇就够了
作者 | 豬哥
來(lái)源 | 裸睡的豬(ID: IT--Pig)
大多數(shù)編程語(yǔ)言的正則表達(dá)式設(shè)計(jì)都師從Perl,所以語(yǔ)法基本相似,不同的是每種語(yǔ)言都有自己的函數(shù)去支持正則,今天我們就來(lái)學(xué)習(xí) Python中關(guān)于 正則表達(dá)式的函數(shù)。
re模塊主要定義了9個(gè)常量、12個(gè)函數(shù)、1個(gè)異常,每個(gè)常量和函數(shù)豬哥都會(huì)通過(guò)實(shí)際代碼案例講解,讓大家能更直觀的了解其作用!
注:為避免出現(xiàn)代碼格式錯(cuò)亂,豬哥盡量使用代碼截圖演示哦。
re模塊簡(jiǎn)介
聊到Python正則表達(dá)式的支持,首先肯定會(huì)想到re庫(kù),這是一個(gè)Python處理文本的標(biāo)準(zhǔn)庫(kù)。
標(biāo)準(zhǔn)庫(kù)的意思表示這是一個(gè)Python內(nèi)置模塊,不需要額外下載,目前Python內(nèi)置模塊大概有300個(gè)。可以在這里查看Python所有的內(nèi)置模塊:https://docs.python.org/3/py-modindex.html#cap-r
因?yàn)閞e是內(nèi)置模塊,所以不需要再下載,使用時(shí)直接引入即可:
import re
re模塊官方文檔:https://docs.python.org/zh-cn/3.8/library/re.html
re模塊庫(kù)源碼:https://github.com/python/cpython/blob/3.8/Lib/re.py
re模塊常量
常量即表示不可更改的變量,一般用于做標(biāo)記。
re模塊中有9個(gè)常量,常量的值都是int類(lèi)型!
上圖我們可以看到,所有的常量都是在RegexFlag枚舉類(lèi)來(lái)實(shí)現(xiàn),這是在Python 3.6做的改版。在Python 3.6以前版本是直接將常量寫(xiě)在re.py中,使用枚舉的好處就是方便管理和使用!
下面我們來(lái)快速學(xué)習(xí)這些常量的作用及如何使用他們,按常用度排序!
1. IGNORECASE
語(yǔ)法:re.IGNORECASE 或簡(jiǎn)寫(xiě)為 re.I
作用:進(jìn)行忽略大小寫(xiě)匹配。
代碼案例:
在默認(rèn)匹配模式下大寫(xiě)字母B無(wú)法匹配小寫(xiě)字母b,而在 忽略大小寫(xiě) 模式下是可以的。
2. ASCII
語(yǔ)法:re.ASCII 或簡(jiǎn)寫(xiě)為 re.A
作用:顧名思義,ASCII表示ASCII碼的意思,讓w,W,b,B,d,D,s和S只匹配ASCII,而不是Unicode。
代碼案例:
在默認(rèn)匹配模式下w+匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII編碼支持的字符)。
注意:這只對(duì)字符串匹配模式有效,對(duì)字節(jié)匹配模式無(wú)效。
3. DOTALL
語(yǔ)法:re.DOTALL 或簡(jiǎn)寫(xiě)為 re.S
作用:DOT表示.,ALL表示所有,連起來(lái)就是.匹配所有,包括換行符。默認(rèn)模式下.是不能匹配行符的。
代碼案例:
在默認(rèn)匹配模式下.并沒(méi)有匹配換行符,而是將字符串分開(kāi)匹配;而在re.DOTALL模式下,換行符與字符串一起被匹配到。
注意:默認(rèn)匹配模式下.并不會(huì)匹配換行符。
4. MULTILINE
語(yǔ)法:re.MULTILINE 或簡(jiǎn)寫(xiě)為 re.M
作用:多行模式,當(dāng)某字符串中有換行符,默認(rèn)模式下是不支持換行符特性的,比如:行開(kāi)頭 和 行結(jié)尾,而多行模式下是支持匹配行開(kāi)頭的。
代碼案例:
正則表達(dá)式中^表示匹配行的開(kāi)頭,默認(rèn)模式下它只能匹配字符串的開(kāi)頭;而在多行模式下,它還可以匹配 換行符后面的字符。
注意:正則語(yǔ)法中^匹配行開(kāi)頭、A匹配字符串開(kāi)頭,單行模式下它兩效果一致,多行模式下A不能識(shí)別。
5. VERBOSE
語(yǔ)法:re.VERBOSE 或簡(jiǎn)寫(xiě)為 re.X
作用:詳細(xì)模式,可以在正則表達(dá)式中加注解!
代碼案例:
默認(rèn)模式下并不能識(shí)別正則表達(dá)式中的注釋,而詳細(xì)模式是可以識(shí)別的。
當(dāng)一個(gè)正則表達(dá)式十分復(fù)雜的時(shí)候,詳細(xì)模式或許能為你提供另一種注釋方式,但它不應(yīng)該成為炫技的手段,建議謹(jǐn)慎考慮后使用!
6.LOCALE
語(yǔ)法:re.LOCALE 或簡(jiǎn)寫(xiě)為 re.L
作用:由當(dāng)前語(yǔ)言區(qū)域決定w,W,b,B和大小寫(xiě)敏感匹配,這個(gè)標(biāo)記只能對(duì)byte樣式有效。這個(gè)標(biāo)記官方已經(jīng)不推薦使用,因?yàn)檎Z(yǔ)言區(qū)域機(jī)制很不可靠,它一次只能處理一個(gè) “習(xí)慣”,而且只對(duì)8位字節(jié)有效。
注意:由于這個(gè)標(biāo)記官方已經(jīng)不推薦使用,而且豬哥也沒(méi)使用過(guò),所以就不給出實(shí)際的案例!
7.UNICODE
語(yǔ)法:re.UNICODE 或簡(jiǎn)寫(xiě)為 re.U
作用:與 ASCII 模式類(lèi)似,匹配unicode編碼支持的字符,但是 Python 3 默認(rèn)字符串已經(jīng)是Unicode,所以有點(diǎn)冗余。
8. DEBUG
語(yǔ)法:re.DEBUG
作用:顯示編譯時(shí)的debug信息。
代碼案例:
雖然debug模式下確實(shí)會(huì)打印編譯信息,但豬哥并不理解這是什么語(yǔ)言 以及表達(dá)的含義,希望了解的朋友能不吝賜教。
9.TEMPLATE
語(yǔ)法:re.TEMPLATE 或簡(jiǎn)寫(xiě)為 re.T
作用:豬哥也沒(méi)搞懂TEMPLATE的具體用處,源碼注釋中寫(xiě)著:disable backtracking(禁用回溯),有了解的同學(xué)可以留言告知!
10. 常量總結(jié)
9個(gè)常量中,前5個(gè)(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用處,兩個(gè)(LOCALE、UNICODE)官方不建議使用、兩個(gè)(TEMPLATE、DEBUG)試驗(yàn)性功能,不能依賴。
常量在re常用函數(shù)中都可以使用,查看源碼可得知。
常量可疊加使用,因?yàn)槌A恐刀际?的冪次方值,所以是可以疊加使用的,疊加時(shí)請(qǐng)使用 |符號(hào),請(qǐng)勿使用+符號(hào)!
最后來(lái)一張思維導(dǎo)圖總結(jié)一下re模塊中的常量吧,需要高清圖或者xmind文件的同學(xué)可在文章末尾獲取。
re模塊函數(shù)
re模塊有12個(gè)函數(shù),豬哥將以功能分類(lèi)來(lái)講解;這樣更具有比較性,同時(shí)也方便記憶。
1.查找一個(gè)匹配項(xiàng)
查找并返回一個(gè)匹配項(xiàng)的函數(shù)有3個(gè):search、match、fullmatch,他們的區(qū)別分別是:
search: 查找任意位置的匹配項(xiàng)
match: 必須從字符串開(kāi)頭匹配
fullmatch: 整個(gè)字符串與正則完全匹配
我們?cè)賮?lái)根據(jù)實(shí)際的代碼案例比較:
案例1:
案例1中search函數(shù)是在字符串中任意位置匹配,只要有符合正則表達(dá)式的字符串就匹配成功,其實(shí)有兩個(gè)匹配項(xiàng),但search函數(shù)值返回一個(gè)。
而match函數(shù)是要從頭開(kāi)始匹配,而字符串開(kāi)頭多了個(gè)字母a,所以無(wú)法匹配,fullmatch函數(shù)需要完全相同,故也不匹配!
案例2:
案例2刪除了text最開(kāi)頭的字母a,這樣match函數(shù)就可以匹配啦,而fullmatch函數(shù)依然不能完全匹配!
案例3:
案例3中,我們只留下一段文字,并且與正則表達(dá)式一致;這時(shí)fullmatch函數(shù)終于可以匹配了。
完整案例:
注意:查找 一個(gè)匹配項(xiàng) 返回的都是一個(gè)匹配對(duì)象(Match)。
2.查找多個(gè)匹配項(xiàng)
講完查找一項(xiàng),現(xiàn)在來(lái)看看查找多項(xiàng)吧,查找多項(xiàng)函數(shù)主要有:findall函數(shù)與finditer函數(shù):
兩個(gè)方法基本類(lèi)似,只不過(guò)一個(gè)是返回列表,一個(gè)是返回迭代器。我們知道列表是一次性生成在內(nèi)存中,而迭代器是需要使用時(shí)一點(diǎn)一點(diǎn)生成出來(lái)的,內(nèi)存使用更優(yōu)。
如果可能存在大量的匹配項(xiàng)的話,建議使用finditer函數(shù),一般情況使用findall函數(shù)基本沒(méi)啥影響。
3.分割
re.split(pattern, string, maxsplit=0, flags=0)函數(shù):用pattern分開(kāi) string ,maxsplit表示最多進(jìn)行分割次數(shù),flags表示模式,就是上面我們講解的常量!
注意:str模塊也有一個(gè) split函數(shù) ,那這兩個(gè)函數(shù)該怎么選呢?str.split函數(shù)功能簡(jiǎn)單,不支持正則分割,而re.split支持正則。
關(guān)于二者的速度如何? 豬哥實(shí)際測(cè)試了一下,在相同數(shù)據(jù)量的情況下使用re.split函數(shù)與str.split函數(shù)執(zhí)行次數(shù)與執(zhí)行時(shí)間對(duì)比圖:
通過(guò)上圖對(duì)比發(fā)現(xiàn),1000次循環(huán)以內(nèi)str.split函數(shù)更快,而循環(huán)次數(shù)1000次以上后re.split函數(shù)明顯更快,而且次數(shù)越多差距越大!
所以結(jié)論是:在 不需要正則支持 且 數(shù)據(jù)量和數(shù)次不多 的情況下使用str.split函數(shù)更合適,反之則使用re.split函數(shù)。
注:具體執(zhí)行時(shí)間與測(cè)試數(shù)據(jù)有關(guān)!
4.替換
替換主要有sub函數(shù)與subn函數(shù),他們功能類(lèi)似!
先來(lái)看看sub函數(shù)的用法:
re.sub(pattern, repl, string, count=0, flags=0)函數(shù)參數(shù)講解:repl替換掉string中被pattern匹配的字符, count表示最大替換次數(shù),flags表示正則表達(dá)式的常量。
值得注意的是:sub函數(shù)中的入?yún)?#xff1a;repl替換內(nèi)容既可以是字符串,也可以是一個(gè)函數(shù)哦!如果repl為函數(shù)時(shí),只能有一個(gè)入?yún)?#xff1a;Match匹配對(duì)象。
re.subn(pattern, repl, string, count=0, flags=0)函數(shù)與re.sub函數(shù)功能一致,只不過(guò)返回一個(gè)元組 (字符串, 替換次數(shù))。
5.編譯正則對(duì)象
compile函數(shù) 與 template函數(shù)將正則表達(dá)式的樣式編譯為一個(gè) 正則表達(dá)式對(duì)象 (正則對(duì)象Pattern),這個(gè)對(duì)象與re模塊有同樣的正則函數(shù)(后面我們會(huì)講解Pattern正則對(duì)象)。
而template函數(shù)與compile函數(shù)類(lèi)似,只不過(guò)是增加了我們之前說(shuō)的re.TEMPLATE模式,我們可以看看源碼。
6.其他
re.escape(pattern) 可以轉(zhuǎn)義正則表達(dá)式中具有特殊含義的字符,比如:.或者*,舉個(gè)實(shí)際的案例:
re.escape(pattern)看似非常好用省去了我們自己加轉(zhuǎn)義,但是使用它很容易出現(xiàn)轉(zhuǎn)義錯(cuò)誤的問(wèn)題,所以并不建議使用它轉(zhuǎn)義,而建議大家自己手動(dòng)轉(zhuǎn)義!
re.purge 函數(shù)作用就是清除 正則表達(dá)式緩存,具體有什么緩存呢?我們來(lái)看看源碼就知道它背地里干了 什么:
看方法大概是清除緩存吧,我們?cè)賮?lái)看看具體的案例:
豬哥在兩個(gè)案例之間使用了re.purge函數(shù)清除緩存,然后分別比較前后案例源碼里面的緩存,看看是否有變化!
7.總結(jié)
同樣,最后來(lái)一張思維導(dǎo)圖總結(jié)一下re模塊中的函數(shù)吧,需要高清圖或者xmind文件的同學(xué)可在末尾獲取。
re模塊異常
re模塊還包含了一個(gè)正則表達(dá)式的編譯錯(cuò)誤,當(dāng)我們給出的正則表達(dá)式是一個(gè)無(wú)效的表達(dá)式(就是表達(dá)式本身有問(wèn)題)時(shí),就會(huì)raise一個(gè)異常!
我們來(lái)看看具體的案例吧:
上圖案例中我們可以看到,在編寫(xiě)正則表達(dá)式中我們多寫(xiě)了一個(gè)后括號(hào),這導(dǎo)致執(zhí)行結(jié)果報(bào)錯(cuò);而且是在其他所有案例執(zhí)行之前,所以說(shuō)明是在正則表達(dá)式編譯時(shí)期就報(bào)錯(cuò)了。
注意:這個(gè)異常一定是 正則表達(dá)式 本身是無(wú)效的,與要匹配的字符串無(wú)關(guān)!
正則對(duì)象Pattern
關(guān)于re模塊的常量、函數(shù)、異常我們都講解完畢,但是完全有必要再講講正則對(duì)象Pattern。
1. 與re模塊 函數(shù)一致
在re模塊的函數(shù)中有一個(gè)重要的函數(shù)compile函數(shù),這個(gè)函數(shù)可以預(yù)編譯返回一個(gè)正則對(duì)象,此正則對(duì)象擁有與re模塊相同的函數(shù),我們來(lái)看看Pattern類(lèi)的源碼。
既然是一致的,那到底該用re模塊還是正則對(duì)象Pattern?
而且,有些同學(xué)可能看過(guò)re模塊的源碼,你會(huì)發(fā)現(xiàn)其實(shí)compile函數(shù)與 其他re函數(shù)(search、split、sub等等) 內(nèi)部調(diào)用的是同一個(gè)函數(shù),最終還是調(diào)用正則對(duì)象的函數(shù)!
也就是說(shuō)下面 兩種代碼寫(xiě)法底層實(shí)現(xiàn) 其實(shí)是一致的:
# re函數(shù)re.search(pattern, text)# 正則對(duì)象函數(shù)compile = re.compile(pattern)compile.search(text)
那還有必要使用compile函數(shù)得到正則對(duì)象再去調(diào)用search函數(shù)嗎?直接調(diào)用re.search 是不是就可以?
2. 官方文檔怎么說(shuō)
關(guān)于到底該用re模塊還是正則對(duì)象Pattern,官方文檔是否有說(shuō)明呢?
官方文檔推薦:在多次使用某個(gè)正則表達(dá)式時(shí)推薦使用正則對(duì)象Pattern以增加復(fù)用性,因?yàn)橥ㄟ^(guò)re.compile(pattern)編譯后的模塊級(jí)函數(shù)會(huì)被緩存!
3. 實(shí)際測(cè)試又如何?
上面官方文檔推薦我們?cè)?多次使用某個(gè)正則表達(dá)式時(shí)使用正則對(duì)象,那實(shí)際情況真的是這樣的嗎?
我們?cè)賹?shí)測(cè)一下吧
豬哥編寫(xiě)了兩個(gè)函數(shù),一個(gè)使用re.search函數(shù)另一個(gè)使用compile.search函數(shù),分別(不同時(shí))循環(huán)執(zhí)行count次(count從1-1萬(wàn)),比較兩者的耗時(shí)!
得出的結(jié)果豬哥繪制成折線圖:
得出的結(jié)論是:100次循環(huán)以內(nèi)兩者的速度基本一致,當(dāng)超出100次后,使用 正則對(duì)象Pattern的函數(shù) 耗時(shí)明顯更短,所以比re模塊要快!
通過(guò)實(shí)際測(cè)試得知:Python 官方文檔推薦 多次使用某個(gè)正則表達(dá)式時(shí)使用正則對(duì)象函數(shù) 基本屬實(shí)!
注意事項(xiàng)
Python 正則表達(dá)式知識(shí)基本講解完畢,最后稍微給大家提一提需要注意的點(diǎn)。
1.字節(jié)串 與 字符串
模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字節(jié)串 (bytes)。但是,Unicode 字符串與8位字節(jié)串不能混用!
2.r 的作用
正則表達(dá)式使用反斜杠(’’)來(lái)表示特殊形式,或者把特殊字符轉(zhuǎn)義成普通字符。
而反斜杠在普通的 Python 字符串里也有相同的作用,所以就產(chǎn)生了沖突。
解決辦法是對(duì)于正則表達(dá)式樣式使用 Python 的原始字符串表示法;在帶有 ‘r’ 前綴的字符串字面值中,反斜杠不必做任何特殊處理。
3.正則查找函數(shù) 返回匹配對(duì)象
查找一個(gè)匹配項(xiàng)(search、match、fullmatch)的函數(shù)返回值都是一個(gè) 匹配對(duì)象Match,需要通過(guò)match.group獲取匹配值,這個(gè)很容易忘記。
另外還需要注意:match.group 與match.groups 函數(shù)的差別!
4.重復(fù)使用某個(gè)正則
如果要重復(fù)使用某個(gè)正則表達(dá)式,推薦先使用 re.compile(pattern)函數(shù)返回一個(gè)正則對(duì)象,然后復(fù)用這個(gè)正則對(duì)象,這樣會(huì)更快!
5.Python 正則面試
筆試可能會(huì)遇到需要使用Python正則表達(dá)式,不過(guò)不會(huì)太難的,大家只要記住那幾個(gè)方法的區(qū)別,會(huì)正確使用,基本問(wèn)題不大。
文章所有內(nèi)容精華豬哥已經(jīng)整理成一份思維導(dǎo)圖:鏈接(或閱讀原文):https://pan.baidu.com/s/10MMpuf6Rcba-gvBo1oIzlw 密碼:y6z3
今日福利
遇見(jiàn)陸奇
同樣作為“百萬(wàn)人學(xué) AI”的重要組成部分,2020 AIProCon 開(kāi)發(fā)者萬(wàn)人大會(huì)將于 7 月 3 日至 4 日通過(guò)線上直播形式,讓開(kāi)發(fā)者們一站式學(xué)習(xí)了解當(dāng)下 AI 的前沿技術(shù)研究、核心技術(shù)與應(yīng)用以及企業(yè)案例的實(shí)踐經(jīng)驗(yàn),同時(shí)還可以在線參加精彩多樣的開(kāi)發(fā)者沙龍與編程項(xiàng)目。參與前瞻系列活動(dòng)、在線直播互動(dòng),不僅可以與上萬(wàn)名開(kāi)發(fā)者們一起交流,還有機(jī)會(huì)贏取直播專(zhuān)屬好禮,與技術(shù)大咖連麥。
- 你點(diǎn)的每個(gè)“在看”,我都認(rèn)真當(dāng)成了AI
總結(jié)
以上是生活随笔為你收集整理的python re 匹配多行_Python正则表达式,看这一篇就够了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python算法入门_GitHub标星2
- 下一篇: python里str什么意思_Pytho