正規表示式貪婪模式與非貪婪模式

weixin_33797791發表於2017-09-10

什麼是正規表示式的貪婪模式和非貪婪模式?

我們先從例子入手:

var str = 'a "witch" and her "boom" is one';
str.match(/".*"/g); 

原本想要匹配的字元為"witch""broom"兩個字串,執行以上的例子看看執行結果:

6882087-00dbe45fae3413a7.png

發現匹配的是"witch" and her "broom"這個字串,之所以出現這個結果,是因為正規表示式的貪婪模式在起作用。

查詢演算法

我們假設自己是正則引擎,模擬一下搜尋實現的過程。
正則引擎先從字串的第0位開始搜尋。

  1. 第一個查詢字元是",正則在第三位匹配到了它:
    6882087-30b6ee86ded28547.png
  2. 引擎嘗試匹配正則的剩餘部分,第二個字元是.,它代表任意字元。隱藏匹配到了w
    6882087-f6e5a93ed217e892.png
  3. .代表任意字元重複一次到多次,因此正則引擎匹配到所有字元:
    6882087-ae774f4be1ea5fda.png
  4. 當文字結束後,點的匹配停止了,但任然有剩餘的正則需要匹配,即:",因此,正則引擎開始倒過來回溯,換句話說,就是一個字元一個字元縮減匹配。
    6882087-863c318ce1fd6943.png

    當匹配縮減後,它開始嘗試匹配剩餘的正則,但"沒有匹配上字元e
  5. 因此正則繼續縮減.所重複的字元,再繼續嘗試:
    6882087-e3a81c31500a5949.png

    引號"沒有匹配上n,又失敗了,繼續嘗試匹配。。。
  6. 正則引擎繼續回溯,一次一次縮減.重複的字元個數,直到剩餘的正則都匹配上:
    6882087-dab32e5da95221ca.png

    現在"終於匹配上了。如果正則是global的,正則引擎會從上次匹配結果之後繼續查詢更多結果。
    由上面的例子可以看出,在貪婪(預設)模式下,正則引擎儘可能多的重複匹配字元

非貪婪模式

非貪婪模式和貪婪模式相反,可通過在代表數量的標示符後放置?來開啟非貪婪模式,如?+?甚至是??

6882087-b9a9579261f6bded.png

可以看到,這次匹配到了"witch""broom"
接下來看看非貪婪模式.?是怎樣運轉的

  1. 第一步和上面類似,引號"被匹配上:
    6882087-30b6ee86ded28547.png
  2. 第二步,.被匹配上:
    6882087-f6e5a93ed217e892.png
  3. 下面是兩者的重要區別。正則引擎嘗試用最小可能的重複次數來進行匹配,因此在.匹配了w後,它立即嘗試"的匹配:
    6882087-a2176adaa61cf56a.png

    沒有匹配上,因為i!="
  4. .重複更多的字元,在進行嘗試:
    6882087-279722c81e6c3abc.png

    又匹配上,繼續。。。
  5. 終於匹配上了:


    6882087-7025499fda3d72b9.png
  6. 因為正則是global的,所以正則引擎繼續後面的匹配,從引號後面的a字元開始。後面又匹配到第二個字串:
    6882087-b8a17aff3fb3d138.png

常見量次符:
? 問號表示某個模式出現0次或1次,等同於{0,1}。
* 星號表示某個模式出現0次或多次,等同於{0,}。
+ 加號表示某個模式出現1次或多次,等同於{1,}。

總結:通過上面的兩個例子,我們發現一些量詞符在預設情況下都是最大可能的匹配,即匹配直到下一個字元不滿足匹配規則為止,這就是貪婪模式。要想匹配到非貪婪模式可以在量詞後面加一個問號。

參考資料:

正規表示式貪婪與非貪婪模式
RegExp物件

相關文章