以前咱們講解了 正則表達式語法 的起源、發展、流派、語法、引擎、優化等相關知識,今天咱們主要來學習一下 正則表達式在 Python語言 中的應用!html
大多數編程語言的正則表達式設計都師從Perl,因此語法基本類似,不一樣的是每種語言都有本身的函數去支持正則,今天咱們就來學習 Python中關於 正則表達式的函數。
re模塊主要定義了9個常量、12個函數、1個異常,每一個常量和函數豬哥都會經過實際代碼案例講解,讓你們能更直觀的瞭解其做用!python
注:爲避免出現代碼格式錯亂,豬哥儘可能使用代碼截圖演示哦。git
聊到Python正則表達式的支持,首先確定會想到re
庫,這是一個Python處理文本的標準庫。github
標準庫的意思表示這是一個 Python內置模塊,不須要額外下載,目前Python內置模塊大概有300個。能夠在這裏查看Python全部的內置模塊: https://docs.python.org/3/py-...
由於re是內置模塊,因此不須要再下載,使用時直接引入便可:面試
import re
re模塊官方文檔:https://docs.python.org/zh-cn...
re模塊庫源碼:https://github.com/python/cpy...正則表達式
常量即表示不可更改的變量,通常用於作標記。編程
re模塊中有9個常量,常量的值都是int類型!
上圖咱們能夠看到,全部的常量都是在RegexFlag枚舉類來實現,這是在Python 3.6作的改版。在Python 3.6之前版本是直接將常量寫在re.py中,使用枚舉的好處就是方便管理和使用!segmentfault
下面咱們來快速學習這些常量的做用及如何使用他們,按經常使用度排序!緩存
語法: re.IGNORECASE 或簡寫爲 re.I編程語言
做用: 進行忽略大小寫匹配。
代碼案例:
在默認匹配模式下大寫字母B沒法匹配小寫字母b,而在 忽略大小寫 模式下是能夠的。
語法: re.ASCII 或簡寫爲 re.A
做用: 顧名思義,ASCII表示ASCII碼的意思,讓 \w
, \W
, \b
, \B
, \d
, \D
, \s
和 \S
只匹配ASCII,而不是Unicode。
代碼案例:
在默認匹配模式下\w+
匹配到了全部字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII編碼支持的字符)。
注意:這隻對字符串匹配模式有效,對字節匹配模式無效。
語法: re.DOTALL 或簡寫爲 re.S
做用: DOT表示.
,ALL表示全部,連起來就是.
匹配全部,包括換行符\n
。默認模式下.
是不能匹配行符\n
的。
代碼案例:
在默認匹配模式下.
並無匹配換行符\n
,而是將字符串分開匹配;而在re.DOTALL模式下,換行符\n
與字符串一塊兒被匹配到。
注意:默認匹配模式下.
並不會匹配換行符\n
。
語法: re.MULTILINE 或簡寫爲 re.M
做用: 多行模式,當某字符串中有換行符\n
,默認模式下是不支持換行符特性的,好比:行開頭 和 行結尾,而多行模式下是支持匹配行開頭的。
代碼案例:
正則表達式中^
表示匹配行的開頭,默認模式下它只能匹配字符串的開頭;而在多行模式下,它還能夠匹配 換行符\n
後面的字符。
注意:正則語法中^
匹配行開頭、\A
匹配字符串開頭,單行模式下它兩效果一致,多行模式下\A
不能識別\n
。
語法: re.VERBOSE 或簡寫爲 re.X
做用: 詳細模式,能夠在正則表達式中加註解!
代碼案例:
默認模式下並不能識別正則表達式中的註釋,而詳細模式是能夠識別的。
當一個正則表達式十分複雜的時候,詳細模式或許能爲你提供另外一種註釋方式,但它不該該成爲炫技的手段,建議謹慎考慮後使用!
語法: re.LOCALE 或簡寫爲 re.L
做用: 由當前語言區域決定 \w
, \W
, \b
, \B
和大小寫敏感匹配,這個標記只能對byte樣式有效。這個標記官方已經不推薦使用,由於語言區域機制很不可靠,它一次只能處理一個 "習慣」,並且只對8位字節有效。
注意: 因爲這個標記官方已經不推薦使用,並且豬哥也沒使用過,因此就不給出實際的案例!
語法: re.UNICODE 或簡寫爲 re.U
做用: 與 ASCII 模式相似,匹配unicode編碼支持的字符,可是 Python 3 默認字符串已是Unicode,因此有點冗餘。
語法: re.DEBUG
做用: 顯示編譯時的debug信息。
代碼案例:
雖然debug模式下確實會打印編譯信息,但豬哥並不理解這是什麼語言 以及表達的含義,但願瞭解的朋友能不吝賜教。
語法: re.TEMPLATE 或簡寫爲 re.T
做用: 豬哥也沒搞懂TEMPLATE的具體用處,源碼註釋中寫着:disable backtracking(禁用回溯),有了解的同窗能夠留言告知!
|
符號,請勿使用+
符號!最後來一張思惟導圖總結一下re模塊中的常量吧。
re模塊有12個函數,豬哥將以功能分類來說解;這樣更具備比較性,同時也方便記憶。
查找並返回一個匹配項的函數有3個:search、match、fullmatch,他們的區別分別是:
咱們再來根據實際的代碼案例比較:
案例1:
案例1中search函數是在字符串中任意位置匹配,只要有符合正則表達式的字符串就匹配成功,其實有兩個匹配項,但search函數值返回一個。
而match函數是要從頭開始匹配,而字符串開頭多了個字母a
,因此沒法匹配,fullmatch函數須要徹底相同,故也不匹配!
案例2:
案例2刪除了text最開頭的字母a,這樣match函數就能夠匹配啦,而fullmatch函數依然不能徹底匹配!
案例3:
案例3中,咱們只留下一段文字,而且與正則表達式一致;這時fullmatch函數終於能夠匹配了。
完整案例:
注意:查找 一個匹配項 返回的都是一個匹配對象(Match)。
講完查找一項,如今來看看查找多項吧,查找多項函數主要有:findall函數 與 finditer函數:
兩個方法基本相似,只不過一個是返回列表,一個是返回迭代器。咱們知道列表是一次性生成在內存中,而迭代器是須要使用時一點一點生成出來的,內存使用更優。
若是可能存在大量的匹配項的話,建議使用finditer函數,通常狀況使用findall函數基本沒啥影響。
re.split(pattern, string, maxsplit=0, flags=0) 函數:用 pattern 分開 string , maxsplit表示最多進行分割次數, flags表示模式,就是上面咱們講解的常量!
注意:str
模塊也有一個 split函數 ,那這兩個函數該怎麼選呢?
str.split函數功能簡單,不支持正則分割,而re.split支持正則。
關於兩者的速度如何? 豬哥實際測試一下,在相同數據量的狀況下使用re.split
函數與str.split
函數執行次數 與 執行時間 對比圖:
經過上圖對比發現,1000次循環之內str.split
函數更快,而循環次數1000次以上後re.split
函數明顯更快,並且次數越多差距越大!
因此結論是:在 不須要正則支持 且 數據量和數次很少 的狀況下使用str.split
函數更合適,反之則使用re.split
函數。
注:具體執行時間與測試數據有關!
替換主要有sub函數 與 subn函數,他們功能相似!
先來看看sub函數的用法:
re.sub(pattern, repl, string, count=0, flags=0) 函數參數講解:repl替換掉string中被pattern匹配的字符, count表示最大替換次數,flags表示正則表達式的常量。
值得注意的是:sub函數中的入參:repl替換內容既能夠是字符串,也能夠是一個函數哦! 若是repl爲函數時,只能有一個入參:Match匹配對象。
re.subn(pattern, repl, string, count=0, flags=0) 函數與 re.sub函數 功能一致,只不過返回一個元組 (字符串, 替換次數)。
compile函數 與 template函數 將正則表達式的樣式編譯爲一個 正則表達式對象 (正則對象Pattern),這個對象與re模塊有一樣的正則函數(後面咱們會講解Pattern正則對象)。
而template函數 與 compile函數 相似,只不過是增長了咱們以前說的re.TEMPLATE 模式,咱們能夠看看源碼。
re.escape(pattern) 能夠轉義正則表達式中具備特殊含義的字符,好比:.
或者 *
,舉個實際的案例:
re.escape(pattern) 看似很是好用省去了咱們本身加轉義,可是使用它很容易出現轉義錯誤的問題,因此並不建議使用它轉義,而建議你們本身手動轉義!
re.purge() 函數做用就是清除 正則表達式緩存,具體有什麼緩存呢?咱們來看看源碼就知道它背地裏幹了 什麼:
看方法大概是清除緩存吧,咱們再來看看具體的案例:
豬哥在兩個案例之間使用了re.purge() 函數清除緩存,而後分別比較先後案例源碼裏面的緩存,看看是否有變化!
一樣最後來一張思惟導圖總結一下re模塊中的函數吧。
re模塊還包含了一個正則表達式的編譯錯誤,當咱們給出的正則表達式是一個無效的表達式(就是表達式自己有問題)時,就會raise一個異常!
咱們來看看具體的案例吧:
上圖案例中咱們能夠看到,在編寫正則表達式中咱們多寫了一個括號,這致使執行結果報錯;並且是在其餘全部案例執行以前,因此說明是在正則表達式編譯時期就報錯了。
注意:這個異常必定是 正則表達式 自己是無效的,與要匹配的字符串無關!
關於re
模塊的常量、函數、異常咱們都講解完畢,可是徹底有必要再講講正則對象Pattern。
在re
模塊的函數中有一個重要的函數 compile函數 ,這個函數能夠預編譯返回一個正則對象,此正則對象擁有與re
模塊相同的函數,咱們來看看Pattern類的源碼。
既然是一致的,那到底該用re模塊 仍是 正則對象Pattern ?
並且,有些同窗可能看過re
模塊的源碼,你會發現其實compile函數 與 其餘 re函數(search、split、sub等等) 內部調用的是同一個函數,最終仍是調用正則對象的函數!
也就是說下面 兩種代碼寫法 底層實現 實際上是一致的:
# re函數 re.search(pattern, text) # 正則對象函數 compile = re.compile(pattern) compile.search(text)
那還有必要使用compile函數 獲得正則對象再去調用 search函數 嗎?直接調用re.search 是否是就能夠?
關於到底該用re模塊 仍是 正則對象Pattern ,官方文檔是否有說明呢?
官方文檔推薦:在屢次使用某個正則表達式時推薦使用正則對象Pattern 以增長複用性,由於經過 re.compile(pattern) 編譯後的模塊級函數會被緩存!
上面官方文檔推薦咱們在 屢次使用某個正則表達式時使用正則對象,那實際狀況真的是這樣的嗎?
咱們在實測一下吧
豬哥編寫了兩個函數,一個使用re.search函數 另外一個使用 compile.search函數 ,分別(不一樣時)循環執行count次(count從1-1萬),比較二者的耗時!
得出的結果豬哥繪製成折線圖:
得出的結論是:100次循環之內二者的速度基本一致,當超出100次後,使用 正則對象Pattern 的函數 耗時明顯更短,因此比re模塊 要快!
經過實際測試得知:Python 官方文檔推薦 屢次使用某個正則表達式時使用正則對象函數 基本屬實!
Python 正則表達式知識基本講解完畢,最後稍微給你們提一提須要注意的點。
模式和被搜索的字符串既能夠是 Unicode 字符串 (str) ,也能夠是8位字節串 (bytes)。 可是,Unicode 字符串與8位字節串不能混用!
正則表達式使用反斜槓('')來表示特殊形式,或者把特殊字符轉義成普通字符。
而反斜槓在普通的 Python 字符串裏也有相同的做用,因此就產生了衝突。
解決辦法是對於正則表達式樣式使用 Python 的原始字符串表示法;在帶有 'r' 前綴的字符串字面值中,反斜槓沒必要作任何特殊處理。
查找一個匹配項(search、match、fullmatch)的函數返回值都是一個 匹配對象Match ,須要經過match.group() 獲取匹配值,這個很容易忘記。
另外還須要注意:match.group() 與match.groups() 函數的差異!
若是要重複使用某個正則表達式,推薦先使用 re.compile(pattern)函數 返回一個正則對象,而後複用這個正則對象,這樣會更快!
筆試可能會遇到須要使用Python正則表達式,不過不會太難的,你們只要記住那幾個方法的區別,會正確使用,基本問題不大。