免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
正則表達式中的回溯

在大多數(shù)現(xiàn)代正則表達式實現(xiàn)中(包括JavaScript所需的),回溯是匹配過程的基本組成部分。它很大程度上也是正則表達式如此美好和強大的根源。然而,回溯計算代價昂貴,如果你不夠小心的話容易失控。雖然回溯是整體性能的唯一因素,理解它的工作原理,以及如何減少使用頻率,可能是編寫高效正則表達式最重要的關(guān)鍵點。因此后面幾節(jié)用較長篇幅討論這個話題。
      當(dāng)一個正則表達式掃描目標(biāo)字符串時,它從左到右逐個掃描正則表達式的組成部分,在每個位置上測試能不能找到一個匹配。對于每一個量詞和分支,都必須決定如何繼續(xù)進行。如果是一個量詞(諸如*,+?,或者{2,}),正則表達式必須決定何時嘗試匹配更多的字符;如果遇到分支(通過|操作符),它必須從這些選項中選擇一個進行嘗試。
      每當(dāng)正則表達式做出這樣的決定,如果有必要的話,它會記住另一個選項,以備將來返回后使用。如果所選方案匹配成功,正則表達式將繼續(xù)掃描正則表達式模板,如果其余部分匹配也成功了,那么匹配就結(jié)束了。但是如果所選擇的方案未能發(fā)現(xiàn)相應(yīng)匹配,或者后來的匹配也失敗了,正則表達式將回溯到最后一個決策點,然后在剩余的選項中選擇一個。它繼續(xù)這樣下去,直到找到一個匹配,或者量詞和分支選項的所有可能的排列組合都嘗試失敗了,那么它將放棄這一過程,然后移動到此過程開始位置的下一個字符上,重復(fù)此過程。


      一、分支和回溯
      下面的例子演示了這一過程是如何處理分支的。
      /h(ello|appy) hippo/.test("hellothere, happyhippo");
      此正則表達式匹配“hellohippo”或“happyhippo”。測試一開始,它要查找一個h,目標(biāo)字符串的第一個字母恰好就是h,它立刻就被找到了。接下來,子表達式(ello|appy)提供了兩個處理選項。正則表達式選擇最左邊的選項(分支選擇總是從左到右進行),檢查ello是否匹配字符串的下一個字符。確實匹配,然后正則表達式又匹配了后面的空格。然而在這一點上它走進了死胡同,因為hippo 中的h 不能匹配字符串中的下一個字母t。此時正則表達式還不能放棄,因為它還沒有嘗試過所有的選擇,隨后它回溯到最后一個檢查點(在它匹配了首字母h 之后的那個位置上)并嘗試匹配第二個分支選項。但是沒有成功,而且也沒有更多的選項了,所以正則表達式認(rèn)為從字符串的第一個字符開始匹配是不能成功的,因此它從第二個字符開始,重新進行查找。它沒有找到h,所以就繼續(xù)向后找,直到第14 個字母才找到,它匹配happy的那個h。然后它再次進入分支過程。這次ello未能匹配,但是回溯之后第二次分支過程中,它匹配了整個字符串“happyhippo”。匹配成功了。
      二、重復(fù)與回溯
      下一個例子顯示了帶重復(fù)量詞的回溯。
      var str = "<p>Para 1.</p>" +
      "<img src='smiley.jpg'>" +
      "<p>Para 2.</p>" +
      "<div>Div.</div>";
      /<p>.*<\/p>/i.test(str);
      正則表達式一上來就匹配了字符串開始的三個字母<p>。然后是.*。點號匹配除換行符以外的任意字符,星號這個貪婪量詞表示重復(fù)零次或多次——匹配盡量多的次數(shù)。因為目標(biāo)字符串中沒有換行符,它將吞噬剩下的全部字符串!不過正則表達式模板中還有更多內(nèi)容需要匹配,所以正則表達式嘗試匹配<。它在字符串末尾匹配不成功,所以它每次回溯一個字符,繼續(xù)嘗試匹配<,直到它回到</div>標(biāo)簽的<位置。然后它嘗試匹配\/(轉(zhuǎn)義反斜杠),匹配成功,然后是p,匹配不成功。正則表達式繼續(xù)回溯,重復(fù)此過程,直到第二段末尾時它終于匹配了</p>。匹配返回成功,它從第一段頭部一直掃描到最后一個的末尾,這可能不是你想要的結(jié)果。
      你可以將正則表達式中的貪婪量詞*改為懶惰(又名非貪婪)量詞*?,以匹配單個段落。懶惰量詞的回溯工作以相反方式進行。當(dāng)正則表達式/<p>.*?<\/p>/推進到.*?時,它首先嘗試全部跳過然后繼續(xù)匹配<\/p>。它這么做是因為*?匹配零次或多次,但盡可能少重復(fù),盡可能少的話那么它就可以重復(fù)零次。但是,當(dāng)隨后的<在字符串的這一點上匹配失敗時,正則表達式回溯并嘗試下一個最小的字符數(shù):一個。它繼續(xù)像這樣向前回溯到第一段的末尾,在那里量詞后面的<\/p>得到完全匹配。
      如果目標(biāo)字符串只有一個段落,你可以看到此正則表達式的貪婪版本和懶惰版本是等價的,但是他們嘗試匹配的過程不同。
      三、回溯失控
      當(dāng)一個正則表達式占用瀏覽器上秒,上分鐘或者更長時間時,問題原因很可能是回溯失控。為說明此問題,考慮下面的正則表達式,它的目標(biāo)是匹配整個HTML文件。此表達式被拆分成多行是為了適合頁面顯示。不像其他大多數(shù)正則表達式那樣,JavaScript沒有選項可使點號匹配任意字符,包括換行符,所以此例中以[\s\S]匹配任意字符。
      /<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>
      [\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/
      此正則表達式匹配正常HTML字符串時工作良好,但是如果目標(biāo)字符串缺少一個或多個標(biāo)簽時,它就會變得十分糟糕。例如</html>標(biāo)簽缺失,那么最后一個[\s\S]*?將擴展到字符串的末尾,因為在那里沒有發(fā)現(xiàn)</html>標(biāo)簽,然后并沒有放棄,正則表達式將察看此前的[\s\S]*?隊列記錄的回溯位置,使它們進一步擴大。正則表達式嘗試擴展倒數(shù)第二個[\s\S]*?——用它匹配</body>標(biāo)簽,就是此前匹配過正則表達式模板<\/body>的那個標(biāo)簽——然后繼續(xù)查找第二個</body>標(biāo)簽直到字符串的末尾。當(dāng)所有這些步驟都失敗了,倒數(shù)第三個[\s\S]*?將被擴展直至字符串的末尾,依此類推。


如果您看完本篇文章感覺不錯,請點擊一下右下角的推薦來支持一下博主,謝謝!
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
如何提高正則表達式執(zhí)行效率
最火的正則表達式,學(xué)起來
JavaScript正則表達式,你真的知道?
正則表達式 學(xué)習(xí)資料整理
13道關(guān)于JavaScript正則表達式的面試題
正則基礎(chǔ)之——貪婪與非貪婪模式(good)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服