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