作為開(kāi)始,我們先看下面的正則:
var str = 'a "witch" and her "broom" is one';
str.match( /".*"/g);
我們本來(lái)預(yù)想上面會(huì)匹配得到"witch"和"broom"兩個(gè)字符串,運(yùn)行上面的例子,卻發(fā)現(xiàn)結(jié)果只匹配到"witch" and her "broom"一個(gè)字符串。
之所以出現(xiàn)這個(gè)結(jié)局,是因?yàn)檎齽t的貪婪模式在起作用。
一、貪婪模式(默認(rèn))
首先我們假設(shè)自己是正則引擎,來(lái)模擬搜索實(shí)現(xiàn)的過(guò)程。
正則引擎先從字符串的第0位開(kāi)始搜索。
- 第一個(gè)查找字符是
",正則引擎在第三個(gè)位置匹配到了它:
-
之后,引擎嘗試匹配正則的剩余部分,第二個(gè)字符是
.,它代表任意字符。引擎匹配到了w:尋找任意字符. -
.代表任意字符重復(fù)一次到多次,因此正則引擎匹配到所有字符一直尋找到最后 -
當(dāng)文本結(jié)束后,點(diǎn)的匹配停止了,但仍然有剩余的正則
"需要匹配,因此正則引擎開(kāi)始倒過(guò)來(lái)回溯,換句話說(shuō),就是一個(gè)字符一個(gè)字符縮減匹配。找到最后了,但最后的字符不是",又要從后往前找"當(dāng)匹配縮減后,它開(kāi)始嘗試匹配剩余的正則,但
"沒(méi)有匹配上字符e。 因此正則繼續(xù)縮減
.所重復(fù)的字符,繼續(xù)嘗試。
-
正則引擎回溯,一次一次縮減
.重復(fù)的字符個(gè)數(shù),直到剩余的正則都匹配上:從后往前終于找到"了 現(xiàn)在
"終于匹配上了。 如果正則是global的,正則引擎會(huì)從上次匹配結(jié)果之后繼續(xù)查找更多結(jié)果。
總結(jié):在貪婪(默認(rèn))模式下,正則引擎盡可能多的重復(fù)匹配字符。
二、非貪婪模式
非貪婪模式和貪婪模式相反,可通過(guò)在代表數(shù)量的標(biāo)識(shí)符后放置?來(lái)開(kāi)啟非貪婪模式,如?、+?甚至是??。
var str = 'a "witch" and her "broom" is one';
str.match(/".*?"/g ) // "witch", "broom"
我們來(lái)看看非貪婪模式.?是怎么運(yùn)轉(zhuǎn)的:
-
第一步和上面類似,引號(hào)
"被匹配上尋找字符串" -
第二步也一樣, '.'被匹配上
尋找任意字符. -
下面是二者的重要區(qū)別。 正則引擎嘗試用最小可能的重復(fù)次數(shù)來(lái)進(jìn)行匹配,因此在
.匹配了w后,它立即嘗試"的匹配找到.后繼續(xù)找"可惜沒(méi)有匹配上,因?yàn)?code>t!="。
-
.重復(fù)更多的字符,再進(jìn)行嘗試往后尋找"又沒(méi)匹配上,繼續(xù)~~
-
下面終于匹配上了
找到"了, 后面可能還有,繼續(xù)找 -
因?yàn)檎齽t是
global的,所以正則引擎繼續(xù)后面的匹配,從引號(hào)后面的a字符開(kāi)始,后面又匹配到第二個(gè)字符串就這樣找到更多的"
總結(jié):在非貪婪模式下,正則引擎盡可能少的重復(fù)匹配字符。