正則詳細教程系列可以看此鏈接的文章哦
https://www.cnblogs.com/poloyy/category/1796055.html
前言
- 學過正則表達式的童鞋肯定都知道貪婪模式和非貪婪模式,這是個重難點!
- 今天我們就來仔細講講它們的區別和具體實例
為什么會有貪婪與非貪婪模式?
首先,貪婪模式和非貪婪模式跟前面講到的量詞密切相關,我們先再來看看有哪些量詞
* + ? 通過 {m,n} 的等價寫法
通過 * 和 + 引入貪婪、非貪婪模式
+ 的栗子
只匹配一個結果
* 的栗子
可以看到會匹配了三個空字符串,我們再通過 Python 代碼看看輸出結果
的確是會有三個空字符串
為什么會匹配到三個空字符串
因為 * 代表 0 到多次,匹配 0 次就是空字符串
小伙伴們你是否有很多個 ?
aaa 之間的空字符串咋沒匹配上呢?
這就要說到我們的貪婪、非貪婪模式了
引入貪婪、非貪婪模式
- 這兩種模式都必須滿足匹配次數的要求才能匹配上
- 貪婪模式,簡單說就是盡可能進行最長匹配
- 非貪婪模式,則會盡可能進行最短匹配
- 正是這兩種模式產生了不同的匹配結果
貪婪模式(Greedy)
在正則中,表示次數的量詞默認是貪婪的,在貪婪模式下,會嘗試盡可能最大長度去匹配
字符串 aaabb 中使用正則 a* 的匹配過程
分析
a* 在匹配開頭的 a 時,會盡量匹配更多的 a,直到第一個 b 不滿足要求為止,匹配上三個 a,后面每次匹配時都得到空字符串
非貪婪匹配(Lazy)
如何從貪婪模式變成非貪婪模式呢
在量詞后面加上 ? ,正則就變成了 a*?
再來看一個栗子
貪婪匹配:匹配上從第一個 " 到最后一個 " 之間的所有內容
非貪婪匹配:找到符合要求的結果
貪婪匹配和非貪婪匹配的區別
獨占模式(Possessive)
前提
這一小節基本都搬了《正則表達式入門課》的內容
什么是獨占模式
- 貪婪模式和非貪婪模式,都需要發生回溯才能完成相應的功能
- 但是在一些場景下,我們不需要回溯,匹配不上返回失敗就好了
- 因此正則中還有另外一種模式,獨占模式,它類似貪婪匹配,但匹配過程不會發生回溯,因此在一些場合下性能會更好
什么是回溯
正則是貪婪
正則:xy{1,3}z
文本:xyyz
匹配結果:xyyz
匹配過程
- {1,3} 會盡可能長地去匹配匹配過程
- 當匹配完 xyy 后,由於 y 要盡可能匹配最長,即三
- 但字符串中后面是個 z 就會導致匹配不上,這時候正則就會向前回溯,吐出當前字符 z,接着用正則中的 z 去匹配
正則是非貪婪模式
正則:xy{1,3}z
文本:xyyz
匹配結果:xyyz
匹配過程
- 由於 y{1,3}? 代表匹配 1 到 3 個 y,盡可能少地匹配
- 匹配上一個 y 之后,也就是在匹配上 text 中的 xy 后
- 正則會使用 z 和 text 中的 xy 后面的 y 比較,發現正則 z 和 y 不匹配
- 這時正則就會向前回溯,重新查看 y 匹配兩個的情況,匹配上正則中的 xyy
- 然后再用 z 去匹配 text 中的 z,匹配成功
看看獨占模式
獨占模式和貪婪模式很像,獨占模式會盡可能多地去匹配,如果匹配失敗就結束,不會進行回溯,這樣的話就比較節省時間
具體寫法
在量詞后加上 +
栗子
正則:xy{1,3}z
文本:xyyz
匹配結果:xyyz
注意事項
Python 和 Go 的標准庫目前都不支持獨占模式
Python 支持獨占模式
需要安裝 regex
pip install regex
Python獨占模式栗子
>>> import regex 4 >>> regex.findall(r'xy{1,3}z', 'xyyz') # 貪婪模式 ['xyyz'] >>> regex.findall(r'xy{1,3}+z', 'xyyz') # 獨占模式 ['xyyz'] >>> regex.findall(r'xy{1,2}+yz', 'xyyz') # 獨占模式 []
再來一個栗子
分析
- a{1,3}+ab 去匹配 aaab 字符串,a{1,3}+ 會把前面三個 a 都用掉,並且不會回溯
- 這樣字符串中內容只剩下 b 了,導致正則中加號后面的 a 匹配不到符合要求的內容, 匹配失敗
- 如果是貪婪模式 a{1,3} 或非貪婪模式 a{1,3}? 都可以匹配上
獨占模式總結
- 獨占模式性能比較好,可以節約匹配的時間和 CPU 資源
- 但有些情況下並不能滿足需求(上面的栗子)
- 要想使用這個模式還要看具體需求,另外還得看你當前使用的語言或庫的支持程度