正則表達(dá)式量詞與貪婪的使用詳解
0.寫(xiě)在前面
在上一篇文章中,我們學(xué)習(xí)了正則的一些基礎(chǔ)元字符,相信大家都已經(jīng)忘卻的差不多了,可以點(diǎn)擊上面的鏈接再溫習(xí)下。
今天我們一起來(lái)學(xué)習(xí)下正則中量詞的三種匹配模式,貪婪模式、非貪婪模式、獨(dú)占模式,這些模式會(huì)改變正則中量詞的匹配行為,是每次貪婪的匹配到更多呢,還是不貪婪見(jiàn)好就收呢,如果不了解這些,我們寫(xiě)出的正則很可能是錯(cuò)誤的,甚至?xí)l(fā)嚴(yán)重的線(xiàn)上性能問(wèn)題。
1.量詞
本篇文章所講的內(nèi)容和量詞關(guān)系比較密切,先回顧下:
我們還可以用 {m,n} 的方式來(lái)表示 * + ? 這3種元字符:
元字符 | 同義表示方法 | 示例 |
---|---|---|
* | {0,} | ab* 可以匹配 a 或者 abb |
+ | {1,} | ab+ 可以匹配 ab 或者 abb 但不能匹配 a |
? | {0,1} | ab? 可以匹配 a 或者 ab 但不能匹配 abb |
2.貪婪模式前傳
在正則中,表示次數(shù)的量詞默認(rèn)是貪婪的,在貪婪模式下,會(huì)盡可能最大長(zhǎng)度的去匹配目標(biāo)字符串,我們用正則 a+ 和 a* 來(lái)匹配字符串 aaabb 測(cè)試一下。
2.1 使用 a+ 進(jìn)行匹配
可以看到只匹配到了1個(gè)結(jié)果 aaa
對(duì)應(yīng)的 Python 代碼如下:
import re print(re.findall(r'a+', 'aaabb')) 輸出:['aaa']
2.2 使用 a* 進(jìn)行匹配
可以看到匹配到了4個(gè)結(jié)果,其中還有3個(gè)是空字符串
對(duì)應(yīng)的 Python 代碼如下:
import re print(re.findall(r'a*', 'aaabb')) 輸出:['aaa', '', '', '']
為什么會(huì)匹配到空字符串呢?因?yàn)樾翘?hào)(*)代表匹配0到多次,匹配0次就是空字符串,那前面還有個(gè) aaa 呢,為什么 aaa 之間的空字符串沒(méi)有被匹配到?
這就引入到了我們今天要講的,貪婪模式與非貪婪模式,從字面上很好理解,貪婪模式就是盡可能多的匹配,非貪婪模式就是盡可能少的匹配。
3.貪婪模式
一起來(lái)分析下上面正則 a* 的匹配過(guò)程:
字符串 | a | a | a | b | b | 空字符串 |
---|---|---|---|---|---|---|
下標(biāo) | 0 | 1 | 2 | 3 | 4 | 5 |
匹配 | 開(kāi)始 | 結(jié)束 | 說(shuō)明 | 匹配內(nèi)容 |
---|---|---|---|---|
第一次 | 0 | 3 | 到第一個(gè)字母b發(fā)現(xiàn)不匹配,輸出aaa | aaa |
第二次 | 3 | 3 | 匹配剩下的bb,發(fā)現(xiàn)匹配不上,輸出空字符串 | 空字符串 |
第三次 | 4 | 4 | 匹配剩下的b,發(fā)現(xiàn)匹配不上,輸出空字符串 | 空字符串 |
第四次 | 5 | 5 | 匹配剩下的空字符串,輸出空字符串 | 空字符串 |
a* 在匹配字符串 aaabb 時(shí),會(huì)盡可能多的把前面的 a 都匹配上,直到第一個(gè)字母 b 不滿(mǎn)足要求為止,匹配上3個(gè) a,后面每次匹配的都是空字符串。
看到這里,相信你已經(jīng)對(duì)貪婪模式有了更深的印象,貪婪模式的特點(diǎn)就是盡可能進(jìn)行最大長(zhǎng)度匹配,就是有多少要多少,下面我們?cè)谝黄饋?lái)看下與它完全相反的匹配模式。
4.非貪婪模式
上面講完了貪婪模式,貪婪模式是盡可能最大長(zhǎng)度匹配,非貪婪模式就是盡可能最小長(zhǎng)度匹配,在量詞的后面加一個(gè)問(wèn)號(hào)(?),就成了非貪婪模式,比如 a*?
對(duì)應(yīng)的 Python 代碼如下:
import re // 貪婪匹配 print(re.findall(r'a*', 'aaabb')) 輸出:['aaa', '', '', ''] // 非貪婪匹配 print(re.findall(r'a*?', 'aaabb')) 輸出:['', 'a', '', 'a', '', 'a', '', '', '']
學(xué)完了貪婪模式與非貪婪模式,你可能會(huì)問(wèn),我什么情況下會(huì)用到呢,下面舉個(gè)栗子感受下:
需求是查找一段字符串中,所有雙引號(hào)括起來(lái)的內(nèi)容,上面使用貪婪匹配與非貪婪匹配的對(duì)比,差別很明顯對(duì)吧。
5.獨(dú)占模式
不管是貪婪模式,還是非貪婪模式,匹配過(guò)程中都需要發(fā)生回溯才能完成想要的功能,但是在有一些場(chǎng)景,我們不需要回溯,匹配不上直接返回失敗就可以了,因此正則匹配中還有另外一種模式,獨(dú)占模式,它和貪婪模式很像,但匹配過(guò)程中不會(huì)發(fā)生回溯,在一些使用場(chǎng)景中性能會(huì)更好。
先來(lái)講講什么是回溯,再舉個(gè)栗子,有一個(gè)正則表達(dá)式和目標(biāo)字符串,我們分別看下在三種匹配模式下都發(fā)生了什么:
5.1 貪婪匹配過(guò)程
正則表達(dá)式:ab{1,3}c
目標(biāo)字符串:abbc
在匹配時(shí),b{1,3} 會(huì)盡可能長(zhǎng)的去匹配目標(biāo)字符串,匹配完 abb 之后,因?yàn)橐M可能長(zhǎng)的匹配(3個(gè) b),目標(biāo)字符串中的c就會(huì)匹配不上,這個(gè)時(shí)候會(huì)發(fā)生向前回溯,吐出當(dāng)前字符 c,用正則中的 c 去匹配,匹配成功。
import regex print(regex.findall(r'ab{1,3}c', 'abbc')) 輸出:['abbc']
5.2 非貪婪匹配過(guò)程
正則表達(dá)式:ab{1,3}?c
目標(biāo)字符串:abbc
在匹配時(shí),b{1,3} 會(huì)盡可能短的去匹配目標(biāo)字符串,匹配完 ab 之后,會(huì)直接用正則 c 去匹配目標(biāo)字符串剩下的 b,匹配不上,發(fā)生向前回溯,重新用正則 b{1,3} 匹配 目標(biāo)字符串剩下的 b,然后正則 c 匹配 目標(biāo)字符串剩下的 c,匹配成功。
import regex print(regex.findall(r'ab{1,3}?c', 'abbc')) 輸出:['abbc']
5.3 獨(dú)占匹配過(guò)程
在量詞后面加上 + 就是獨(dú)占模式。
正則表達(dá)式:ab{1,2}+bc
目標(biāo)字符串:abbc
在匹配時(shí),b{1,2} 會(huì)盡可能長(zhǎng)的去匹配目標(biāo)字符串,匹配完 abb 之后,會(huì)用正則 b 匹配目標(biāo)字符串剩下的 c,匹配不上,不回溯,匹配失敗。
import regex print(regex.findall(r'ab{1,2}+bc', 'abbc')) 輸出:[]
6.寫(xiě)在最后
最后在總結(jié)下上面講到的內(nèi)容:
到這里,正則表達(dá)式的量詞與貪婪就講完了,如果有問(wèn)題可以給我留言評(píng)論,謝謝。
正則表達(dá)式在線(xiàn)校驗(yàn)工具:https://regex101.com/
到此這篇關(guān)于正則表達(dá)式量詞與貪婪的使用詳解的文章就介紹到這了,更多相關(guān)正則表達(dá)式 量詞與貪婪內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
精通 JavaScript中的正則表達(dá)式手機(jī)整理 推薦
精通 JS正則表達(dá)式,想學(xué)習(xí)js正則表達(dá)式的朋友非常值得看,整理的比較不錯(cuò)。2009-10-10修改月光博客網(wǎng)站中PHP常用正則表達(dá)式中出現(xiàn)的錯(cuò)誤
這篇文章主要介紹了修改月光博客網(wǎng)站中PHP常用正則表達(dá)式中出現(xiàn)的錯(cuò)誤,需要的朋友可以參考下2014-04-04正則表達(dá)式對(duì)qq號(hào)碼校驗(yàn)
這篇文章主要介紹了正則表達(dá)式對(duì)qq號(hào)碼進(jìn)行校驗(yàn)的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-06-068個(gè)你應(yīng)該了解的正則表達(dá)式提高你的工作效率
正則表達(dá)式也可以被當(dāng)作是一門(mén)語(yǔ)言,入門(mén)時(shí)可能很吃力,不過(guò)一旦學(xué)會(huì)了就方便很多,在處理一些比較復(fù)雜的替換時(shí),正則表達(dá)式就會(huì)發(fā)揮它的真正作用,本文整理了一些常用的正則,感興趣的朋友可以了解下,或許對(duì)你有所幫助2013-01-01編寫(xiě)高質(zhì)量的js之正確理解正則表達(dá)式回溯
在正則表達(dá)式實(shí)現(xiàn)中,回溯是匹配過(guò)程的基本組成部分,它是正則表達(dá)式如此好用和強(qiáng)大的根源。然而,回溯計(jì)算代價(jià)很高,如果設(shè)計(jì)失誤,將導(dǎo)致失控。回溯是影響整體性能的唯一因素,理解它的工作原理,以及如何減小使用頻率,可能是編寫(xiě)高效正則表達(dá)式的關(guān)鍵點(diǎn)2016-12-12