什么是正則表達(dá)式的貪婪模式和非貪婪模式?
我們先從例子入手:
var str = 'a "witch" and her "boom" is one';
str.match(/".*"/g);
原本想要匹配的字符為"witch"
和"broom"
兩個(gè)字符串,運(yùn)行以上的例子看看運(yùn)行結(jié)果:
發(fā)現(xiàn)匹配的是
"witch" and her "broom"
這個(gè)字符串,之所以出現(xiàn)這個(gè)結(jié)果,是因?yàn)檎齽t表達(dá)式的貪婪模式在起作用。
查找算法
我們假設(shè)自己是正則引擎,模擬一下搜索實(shí)現(xiàn)的過程。
正則引擎先從字符串的第0位開始搜索。
- 第一個(gè)查找字符是
"
,正則在第三位匹配到了它:
- 引擎嘗試匹配正則的剩余部分,第二個(gè)字符是
.
,它代表任意字符。隱藏匹配到了w
:
-
.
代表任意字符重復(fù)一次到多次,因此正則引擎匹配到所有字符:
- 當(dāng)文本結(jié)束后,點(diǎn)的匹配停止了,但任然有剩余的正則需要匹配,即:
"
,因此,正則引擎開始倒過來回溯,換句話說,就是一個(gè)字符一個(gè)字符縮減匹配。
當(dāng)匹配縮減后,它開始嘗試匹配剩余的正則,但"
沒有匹配上字符e
。 - 因此正則繼續(xù)縮減
.
所重復(fù)的字符,再繼續(xù)嘗試:
引號(hào)"
沒有匹配上n
,又失敗了,繼續(xù)嘗試匹配。。。 - 正則引擎繼續(xù)回溯,一次一次縮減
.
重復(fù)的字符個(gè)數(shù),直到剩余的正則都匹配上:
現(xiàn)在"
終于匹配上了。如果正則是global
的,正則引擎會(huì)從上次匹配結(jié)果之后繼續(xù)查找更多結(jié)果。
由上面的例子可以看出,在貪婪(默認(rèn))模式下,正則引擎盡可能多的重復(fù)匹配字符
非貪婪模式
非貪婪模式和貪婪模式相反,可通過在代表數(shù)量的標(biāo)示符后放置?
來開啟非貪婪模式,如?
、+?
甚至是??
。
可以看到,這次匹配到了
"witch"
和"broom"
。接下來看看非貪婪模式
.?
是怎樣運(yùn)轉(zhuǎn)的
- 第一步和上面類似,引號(hào)
"
被匹配上:
- 第二步,
.
被匹配上:
- 下面是兩者的重要區(qū)別。正則引擎嘗試用最小可能的重復(fù)次數(shù)來進(jìn)行匹配,因此在
.
匹配了w
后,它立即嘗試"
的匹配:
沒有匹配上,因?yàn)?code>i!="。 -
.
重復(fù)更多的字符,在進(jìn)行嘗試:
又匹配上,繼續(xù)。。。 -
終于匹配上了:
- 因?yàn)檎齽t是
global
的,所以正則引擎繼續(xù)后面的匹配,從引號(hào)后面的a
字符開始。后面又匹配到第二個(gè)字符串:
常見量次符:
? 問號(hào)表示某個(gè)模式出現(xiàn)0次或1次,等同于{0,1}。
* 星號(hào)表示某個(gè)模式出現(xiàn)0次或多次,等同于{0,}。
+ 加號(hào)表示某個(gè)模式出現(xiàn)1次或多次,等同于{1,}。
總結(jié):通過上面的兩個(gè)例子,我們發(fā)現(xiàn)一些量詞符在默認(rèn)情況下都是最大可能的匹配,即匹配直到下一個(gè)字符不滿足匹配規(guī)則為止,這就是貪婪模式。要想匹配到非貪婪模式可以在量詞后面加一個(gè)問號(hào)。