亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Regex > 正文

編寫高質量的js之正確理解正則表達式回溯

2020-03-16 20:56:21
字體:
來源:轉載
供稿:網友

當一個正則表達式掃描目標字符串時,從左到右逐個掃描正則表達式的組成部分,在每個位置上測試能不能找到一個匹配。對于每一個量詞和分支,都必須確定如何繼續進行。如果是一個量詞(如*、+?或者{2,}),那么正則表達式必須確定何時嘗試匹配更多的字符;如果遇到分支(通過|操作符),那么正則表達式必須從這些選項中選擇一個進行嘗試。

當正則表達式做出這樣的決定時,如果有必要,它會記住另一個選項,以備返回后使用。如果所選方案匹配成功,正則表達式將繼續掃描正則表達式模板,如果其余部分匹配也成功了,那么匹配就結束了。但是,如果所選擇的方案未能發現相應匹配,或者后來的匹配也失敗了,正則表達式將回溯到最后一個決策點,然后在剩余的選項中選擇一個。繼續這樣,直到找到一個匹配,或者量詞和分支選項的所有可能的排列組合都嘗試失敗后放棄這一過程,然后移動到此過程開始位置的下一個字符上,重復此過程。

例如,下面的代碼演示了這一過程是如何通過回溯處理分支的。

/h(ello|appy) hippo/.test("hello there, happy hippo");

上面一行正則表達式用于匹配“hello hippo”或“happy hippo”。測試一開始要查找一個h,目標字符串的第一個字母恰好就是h,立刻就找到了。接下來,子表達式(ello|appy)提供了兩個處理選項。正則表達式選擇最左邊的選項(分支選擇總是從左到右進行),檢查ello 是否匹配字符串的下一個字符,確實匹配,然后正則表達式又匹配了后面的空格。

然而,在接下來的匹配中正則表達式“走進了死胡同”,因為hippo 中的h 不能匹配字符串中的下一個字母t。此時正則表達式還不能放棄,因為它還沒有嘗試過所有的選擇,隨后它回溯到最后一個檢查點(在匹配了首字母h 之后的那個位置上)并嘗試匹配第二個分支選項。但由于匹配沒有成功,而且也沒有更多的選項了,正則表達式認為從字符串的第一個字符開始匹配是不能成功的,因此它從第二個字符開始重新進行查找。正則表達式沒有找到h,繼續向后找,直到第14 個字母才找到,它匹配happy 的那個h。隨后正則表達式再次進入分支過程,這次ello 未能匹配,但在回溯之后的第二次分支中,它匹配了整個字符串“happy hippo”,匹配成功了。

再如,下面代碼演示了帶重復量詞的回溯。

var str = "<p>Para 1.</p>" +"<img src='smiley.jpg'>" +"<p>Para 2.</p>" +"<div>Div.</div>";/<p>.*<//p>/i.test(str);

正則表達式先匹配了字符串開始的3個字母<p>,然后是.*。點號表示匹配除換行符以外的任意字符,星號這個“貪婪”量詞表示重復零次或多次,匹配盡量多的次數。因為目標字符串中沒有換行符,正則表達式將匹配剩下的全部字符串!不過由于正則表達式模板中還有更多內容需要匹配,所以正則表達式嘗試匹配<。由于在字符串末尾匹配不成功,因此每次回溯一個字符,繼續嘗試匹配<,直到正則表達式回到</div>標簽的<位置。接下來嘗試匹配//(轉義反斜杠),匹配成功,然后匹配p,匹配不成功。正則表達式繼續回溯,重復此過程,直到第二段末尾時終于匹配了</p>。匹配返回成功需要從第一段頭部一直掃描到最后一個的末尾,這可能不是我們想要的結果。

將正則表達式中的“貪婪”量詞*改為“懶惰”(又名“非貪婪”)量詞*?,以匹配單個段落。“懶惰”量詞的回溯工作以相反方式進行。當正則表達式/<p>.*?<//p>/推進到.*?時,首先嘗試全部跳過,然后繼續匹配<//p>。

這樣做是因為*?匹配零次或多次,盡可能少重復,盡可能少意味著可以重復零次。但是,當隨后的<在字符串的這一點上匹配失敗時,正則表達式回溯并嘗試下一個最小的字符數:1個。正則表達式繼續像這樣向前回溯到第一段的末尾,在那里量詞后面的<//p>得到完全匹配。

如果目標字符串只有一個段落,那么此正則表達式的“貪婪”版本和“懶惰”版本是等價的,但嘗試匹配的過程不同。

當一個正則表達式占用瀏覽器幾秒甚至更長時間時,問題原因很可能是回溯失控。為說明此問題,給出下面的正則表達式,它的目標是匹配整個HTML文件。此表達式被拆分成多行是為了適合頁面顯示。與其他正則表達式不同,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 字符串時工作良好,但當目標字符串缺少一個或多個標簽時,就會變得十分糟糕。例如</html>標簽缺失,最后一個[/s/S]*?將擴展到字符串的末尾,因為在那里沒有發現</html>標簽,然后正則表達式將查看此前的[/s/S]*?隊列記錄的回溯位置,使它們進一步擴大。正則表達式嘗試擴展倒數第二個[/s/S]*?—用它匹配</body>標簽,就是此前匹配過正則表達式模板<//body>的那個標簽,然后繼續查找第二個</body>標簽,直到字符串的末尾。當所有這些步驟都失敗時,倒數第三個[/s/S]*?將被擴展,直至字符串的末尾,依此類推。

此類問題的解決辦法在于盡可能具體地指出分隔符之間的字符匹配形式,如模板“.*?”用于匹配雙引號包圍的一個字符串。用更具體的[^"/rn]*取代過于寬泛的.*?就去除了回溯時可能發生的幾種情況,如嘗試用點號匹配引號,或者擴展搜索超出預期范圍。

在HTML 的例子中解決辦法不是那么簡單。不能使用否定字符類型,如用[^<]替代[/s/S],因為在搜索過程中可能會遇到其他類型的標簽。但是,可以通過重復一個非捕獲組來達到同樣效果,它包含一個回溯(阻塞下一個所需的標簽)和[/s/S](任意字符)元序列。這樣可以確保中間位置上查找的每個標簽都會失敗。然后,更重要的是,[/s/S]模板在回溯過程中阻塞的標簽在被發現之前不能被擴展。應用此方法后對正則表達式的最終修改如下:

/<html>(?:(?!<head>)[/s/S])*<head>(?:(?!<title>)[/s/S])*<title>(?:(?!<//title>)[/s/S])*<//title>(?:(?!<//head>)[/s/S])*<//head>(?:(?!<body>)[/s/S])*<body>(?:(?!<//body>)[/s/S])*<//body>(?:(?!<//html>)[/s/S])*<//html>/

雖然這樣做消除了潛在的回溯失控,并允許正則表達式在匹配不完整HTML字符串失敗時的使用時間與文本長度呈線性關系,但是正則表達式的效率并沒有提高。像這樣為每個匹配字符進行多次前瞻,缺乏效率,而且成功匹配過程也相當慢。匹配較短字符串時使用此方法相當不錯,而匹配一個HTML 文件可能需要前瞻并測試上千次。


注:相關教程知識閱讀請移步到正則表達式頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
热久久免费视频精品| 国内免费久久久久久久久久久| 91精品国产91久久久久| 久久好看免费视频| 久久久久久中文| 欧美国产在线视频| 欧美老女人在线视频| 日本一区二区三区四区视频| 精品久久久久久久久久ntr影视| 欧美夫妻性视频| 欧美大肥婆大肥bbbbb| 亚洲欧洲激情在线| 精品国产91乱高清在线观看| 欧美精品激情blacked18| 国内精久久久久久久久久人| 亚洲欧美国产精品va在线观看| 激情av一区二区| 色先锋资源久久综合5566| 成人精品在线视频| 亚洲精品乱码久久久久久按摩观| 日韩精品在线观看网站| 国产精品手机播放| 福利视频第一区| 国产日韩精品入口| 国产成人免费av电影| 日韩欧美国产骚| 热99精品只有里视频精品| 91在线中文字幕| 欧美在线视频观看免费网站| 成人精品久久久| 国产成人aa精品一区在线播放| 日韩久久精品电影| 日韩欧美亚洲成人| 欧美日韩国产中文字幕| 亚洲欧洲国产精品| 欧美—级a级欧美特级ar全黄| 亚洲人成在线免费观看| 国产精品三级网站| 国产精品视频一区二区高潮| 欧美丝袜美女中出在线| 亚洲天堂av女优| 国产成人精品av| 成人黄色av网站| 成人观看高清在线观看免费| 日韩视频在线观看免费| 国产99久久精品一区二区 夜夜躁日日躁| 亲子乱一区二区三区电影| 欧美国产欧美亚洲国产日韩mv天天看完整| 精品国模在线视频| 亚洲欧美在线x视频| 欧美日韩国产一区二区| 国产精品免费福利| 欧美成aaa人片在线观看蜜臀| 久久91亚洲精品中文字幕| 欧美在线不卡区| 日韩精品一二三四区| 欧美与黑人午夜性猛交久久久| 成人国产在线视频| 欧美理论电影网| 亚洲人成在线一二| 欧美国产精品人人做人人爱| 91九色国产在线| 大荫蒂欧美视频另类xxxx| 91国内在线视频| 97色在线视频观看| 亚洲精品之草原avav久久| 97**国产露脸精品国产| 国产精品嫩草影院一区二区| 欧美性开放视频| 日韩有码视频在线| 亚洲午夜精品久久久久久久久久久久| 欧美性猛交xxxx乱大交3| 中文字幕免费国产精品| 国产精品自产拍在线观| 岛国av一区二区| 国产精品网站大全| 久久久日本电影| 97视频国产在线| 国产日韩欧美中文| 国产成人一区三区| 成人免费视频在线观看超级碰| 欧美性猛交xxxx富婆| 日韩精品视频在线观看免费| 永久免费看mv网站入口亚洲| 国产精品精品久久久久久| 不卡av在线播放| 成人福利网站在线观看| 成人在线国产精品| 91免费人成网站在线观看18| www.午夜精品| 国产香蕉精品视频一区二区三区| 欧美成人免费全部| 深夜福利91大全| 欧美日韩一区二区免费视频| 国产精品视频99| 欧美日韩午夜激情| 亚洲bt欧美bt日本bt| 人人做人人澡人人爽欧美| 国产亚洲欧美日韩精品| 亚洲第一精品久久忘忧草社区| 日韩中文字幕免费| 亚洲人成在线一二| 中文字幕日韩在线观看| 亚洲在线视频观看| 性欧美xxxx视频在线观看| 精品女厕一区二区三区| 九九视频这里只有精品| 色视频www在线播放国产成人| 亚洲一区二区三区四区视频| 国产女人18毛片水18精品| 色中色综合影院手机版在线观看| 国产一区二区视频在线观看| 日韩精品高清在线观看| 亚洲第一区在线观看| 久久精品国产免费观看| 国产精品视频最多的网站| 日韩av片免费在线观看| 久久精品这里热有精品| 久久久av一区| 精品国产一区二区三区久久久狼| 岛国av一区二区三区| 成人h视频在线| 日韩久久精品电影| 国产精品专区一| 久久精品国产电影| 91香蕉国产在线观看| 亚洲欧美激情四射在线日| 91精品国产91久久久久久久久| 久久久亚洲国产| 国产成人精品一区二区| 亚洲天堂网在线观看| 日本精品久久久久影院| 久久久久亚洲精品成人网小说| 亚洲在线观看视频| 7777精品久久久久久| 一区二区成人精品| 国产精品美女久久久久av超清| 国产欧美一区二区| 91久久久久久国产精品| 欧美性高潮床叫视频| 亚洲天堂2020| 国产精品福利小视频| 日韩精品一区二区三区第95| 国产精品入口免费视频一| 一本一本久久a久久精品综合小说| 精品久久久久久久大神国产| 91精品国产自产在线观看永久| 日韩欧美亚洲国产一区| 91在线高清免费观看| 在线日韩中文字幕| 欧美一区二区色| 欧美日韩中文在线观看| 亚洲精品国精品久久99热一| 亚洲色图av在线| 欧美大尺度电影在线观看| 欧美精品国产精品日韩精品| 亚洲电影中文字幕| 国产在线不卡精品| 97久久伊人激情网| 欧美成人黑人xx视频免费观看| 久久影院资源站| 黄色一区二区三区| 欧美一乱一性一交一视频| 精品久久久久久久久国产字幕|