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

首頁 > 編程 > regex > 正文

PHP正則表達式的效率 回溯與固化分組

2020-01-20 22:17:23
字體:
來源:轉載
供稿:網友
先來看下問題。

字符串
復制代碼 代碼如下:

$str = '<script>123456</script>';

正則表達式為
復制代碼 代碼如下:

$strRegex1 = '%<script>.+<//script>%';
$strRegex2 = '%<script>.+?<//script>%';
$strRegex3 = '%<script>(?:(?!<//script>).)+<//script>%';

這三個正則,分別會造成幾次回溯呢??
答案:
復制代碼 代碼如下:

$strRegex1 = '%<script>.+<//script>%'; //9次,記得區別轉義符號。
$strRegex2 = '%<script>.+?<//script>%'; //5次
$strRegex3 = '%<script>(?:(?!<//script>).)+<//script>%'; //7次

對于第一種貪婪匹配的匹配規則,回溯的9次是正則【】對字符串“”匹配時,構成的回溯,回溯的次數,恰好是字符串的長度。
第二種非貪婪匹配規則,回溯5次,是正則【.+?】對字符串“123456”匹配時構成的回溯?;厮莸拇螖?,為字符串長度減去最小次數。也就是6-1=5次。如果正則表達式為【.*?】那么,回溯次數就是6次了。
第三種正則是零寬斷言,或者叫環視。(暫且不說。)
在NFA正則引擎中,回溯是他的靈魂,所以,不管是貪婪,非貪婪,環視等寫法中肯定會有回溯的出現的,這個我們無法避免(用詞不太準確),但是,我們可以減少回溯的次數,或者保護其中一部分匹配的規則不進行回溯。

對于上篇BLOG上提到的鳥哥談到一個非貪婪引起的大量回溯問題,大家可以知道,回溯,確實是浪費資源的罪魁禍首,那么,我們能否不讓其回溯呢?
答案是肯定的,NFA引擎中,有個概念,叫固化分組。引用一下書上的概念
復制代碼 代碼如下:

具體來說,使用「(?>…)」的匹配與正常的匹配并無差別,但是如果匹配進行到此結構之后(也就是,進行到閉括號之后),那么此結構體中的所有備用狀態都會被放棄。也就是說,在固化分組匹配結束時,它已經匹配的文本已經固化為一個單元,只能作為整體而保留或放棄。括號內的子表達式中未嘗試過的備用狀態都不復存在了,所以回溯永遠也不能選擇其中的狀態(至少是,當此結構匹配完成時,“鎖定(locked in)”在其中的狀態)。

那么,固化分組到底有什么用處呢?我們來舉個例子。(找不到合適的例子,俺只好借用一下書上的例子了)
比如要處理一批數據,原來格式為123.456,后來因為浮點數顯示問題,部分數據格式變為123.456000000789這種,,要求做到只保留小數點后面2-3位,但是,最后一位不能為0,這個正則如何寫呢?(下面直接考慮小數點后面的數字),寫出正則之后,我們還要用這個正則去匹配數據,把原來的數據替換成匹配的結果。
首先,我們可以立刻寫出這樣的正則【/./d/d[1-9]?/d*】,PHP代碼為
復制代碼 代碼如下:

$str = preg_replace('/.(/d/d[1-9]?)/d*','//1',$str); //匹配結果的group1進行反向引用

很明顯,這種寫法,對于部分數據格式為123.456的這種格式,白白的處理了一遍,為了提高效率,我們還要對這個正則進行處理。從123.456這個字符串跟其他的比較一下,我們發現,是疑問123.456這個數據后面沒數字了,所以,白白處理一遍。那好辦,我們對這個正則改造一下,把后面的量詞*改成+,這樣對于123.45 小數點后面1,2位數字的,不會去白白處理,而且,對三位以上數字的,處理正常。其PHP代碼為
復制代碼 代碼如下:

$str = preg_replace('/.(/d/d[1-9]?)/d+','//1',$str);

好了,這個正則真的沒問題嗎??確定嗎?上篇博文,我們了解了匹配原理,那么,我們也分析一下這個正則的匹配過程吧。
字符串"123.456",正則表達式為【/.(/d/d[1-9]?)/d+】,我們來看下
首先(小數點前123不說了),【/.】匹配".",匹配成功,把控制權給下一個【/d】,【/d】匹配“4”成功,把控制權給第二個【/d】,這個【/d】匹配“5”成功,然后,把控制權給了【[1-9]?】,由于量詞是【?】,正則表達式遵循“量詞優先匹配”,而且,此處是【?】,還會留下一個回溯點。然后匹配"6"成功,然后把控制權給【/d+】,【/d+】發現后面沒字符了,最遵循“后進先出”規則,回到上一個回溯點,進行匹配,這時,【[1-9]?】會交還出其匹配的字符“6”,【[1-9]?】匹配“6”成功。匹配完成了。大家發現【(/d/d[1-9]?)】匹配的結果確是"45",并不是我們想要的“456”,“6”被【/d+】匹配去了。那么,我們該如何辦呢? 能否讓【[1-9]?】匹配一旦成功,不進行回溯呢?這就用到了我們上面說的"固化分組", PHP(preg_replace函數)中使用的正則引擎支持固化分組,我們根據固化分組的寫法,可以把代碼改成如下方式
復制代碼 代碼如下:

$str = preg_replace('/.(/d/d(?>[1-9]?))/d+','//1',$str);

改成這樣的話,那字符串“123.456“是不符合要求,不會被匹配的。那我們就可以實現我們的要求了。

從上面的例子中,知道了固化分組的作用,那么對于鳥哥BLOG上寫的那個非貪婪的回溯問題,我們能否也對其改造,使得其不回溯呢?
先看下鳥哥給的答案
復制代碼 代碼如下:

/<script>[^<]*<//script>/is

鳥哥寫的很精悍。排除“<”之外的所有字符都符合,而且,中間部分不回溯,效率高。可是,如果中間有字符“<“的話(如下代碼)
復制代碼 代碼如下:

<script>
if a < b
</script>

那鳥哥的這個正則就不能匹配,就不能實現我們想要的功能了。
那我們可以根據 固化分組、環視(零寬斷言)來實現這個要求,最后,CFC4N給出的正則以及PHP代碼事例如下
復制代碼 代碼如下:

$reg = '%<script>(?>[^<]*)(?>(?!</?script>)<[^<]*)*</script>%is';
$str = str_pad("<script>", 111111, "*"); //字符長度大于PHP回溯限制的100000
$str .= 'if a < b ; if b > c;</script>'; //隨便加幾個包含 < > 的測試字符
$ret = preg_replace($reg, "OK", $str);
print_r($ret); //打印結果 OK,證明匹配正確
var_dump(preg_last_error()); //上一次匹配錯誤。其輸出為 int(0)

嗨,同學,你看明白了嗎?

以上為小菜CFC4N的愚文,如有錯誤,歡迎指出。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美壮男野外gaytube| 九九热视频这里只有精品| 久久免费在线观看| 欧美日韩国产综合视频在线观看中文| 日韩综合中文字幕| 91国偷自产一区二区三区的观看方式| 亚洲综合精品一区二区| 91精品国产乱码久久久久久久久| 日韩av一区二区在线观看| 久久99久国产精品黄毛片入口| 欧美激情欧美激情在线五月| 亚洲精品wwwww| 久久久久久久国产精品视频| 欧美午夜丰满在线18影院| 精品国产一区二区三区久久狼5月| 国产精品久久久久久搜索| 国产精品久久久久免费a∨| 国产专区欧美专区| 亚洲第一区中文字幕| 亚洲天堂日韩电影| 欧美一级免费看| 精品无码久久久久久国产| 91影视免费在线观看| 欧美激情视频一区二区三区不卡| 日韩精品久久久久久福利| 久久精品美女视频网站| 日韩在线视频观看正片免费网站| 亚洲一区二区免费| 91精品久久久久久久久| 亚洲www永久成人夜色| 亚洲人成在线一二| 欧美性猛交xxxx免费看| 欧美国产亚洲精品久久久8v| 欧美最顶级丰满的aⅴ艳星| 在线电影av不卡网址| 国外成人性视频| 亚洲精品美女久久| 美日韩丰满少妇在线观看| 国产精品三级久久久久久电影| 伊人久久大香线蕉av一区二区| 久久视频国产精品免费视频在线| 亚洲欧美成人一区二区在线电影| 国产精品视频白浆免费视频| 久久久伊人欧美| 国产亚洲视频在线观看| 深夜福利91大全| 欧美中文在线字幕| 国产精品黄色av| 亚洲精品国精品久久99热| 超碰91人人草人人干| 欧美精品九九久久| 成人免费看黄网站| 亚洲国产成人在线视频| 91亚洲精品在线观看| 9.1国产丝袜在线观看| 日本欧美在线视频| 九色精品免费永久在线| 精品毛片网大全| 国产精品成人一区二区| 一区二区三区四区在线观看视频| 国产精品免费一区二区三区都可以| 久久久久久久一区二区| 91亚洲精品在线| 日韩电影视频免费| 一区二区三区美女xx视频| 国产一区欧美二区三区| 久久精品这里热有精品| 国产午夜精品美女视频明星a级| 亚洲国产精品热久久| 国产亚洲a∨片在线观看| 精品国产乱码久久久久久天美| 97人洗澡人人免费公开视频碰碰碰| 欧美激情久久久久久| 色综合久久久888| 亚洲精品资源美女情侣酒店| 久久福利视频导航| 国产精品视频免费在线观看| 日韩欧美国产激情| 亚洲国模精品私拍| 国语自产精品视频在线看抢先版图片| 欧美日韩激情美女| 欧美日韩在线视频一区二区| 欧美日韩裸体免费视频| 亚洲色图50p| 青青久久av北条麻妃海外网| 亚洲激情视频在线播放| 亚洲第一中文字幕| 97视频国产在线| 日韩av在线网站| 性亚洲最疯狂xxxx高清| 欧美日韩国产中文字幕| 久久久精品国产一区二区| 亚洲а∨天堂久久精品9966| 精品一区二区三区四区| 久久中文字幕视频| 国产91精品视频在线观看| 亚洲欧美日韩精品| 国产亚洲欧洲高清| 国产精品狼人色视频一区| 欧美日本中文字幕| 国产一区二区在线免费视频| 韩国一区二区电影| 亚洲国产欧美一区二区三区同亚洲| 欧美激情a∨在线视频播放| 亚洲成人中文字幕| 色偷偷91综合久久噜噜| 日韩精品在线免费观看| 国产69精品久久久久9| 91在线观看免费高清完整版在线观看| 最近2019中文字幕mv免费看| 亚洲欧美中文另类| 国产精品入口免费视频一| 国产精品免费福利| 国产午夜精品免费一区二区三区| 精品国产欧美一区二区五十路| 最新日韩中文字幕| 亚洲成人黄色网| 亚洲sss综合天堂久久| www.美女亚洲精品| 美女av一区二区| 欧美风情在线观看| 亚洲欧美综合另类中字| 欧美高清视频免费观看| 色哟哟网站入口亚洲精品| 亚洲视频在线观看视频| 91色p视频在线| 日本伊人精品一区二区三区介绍| 激情av一区二区| 久久网福利资源网站| 国产成人亚洲综合青青| 亚洲一区二区三区四区视频| 欧美大尺度电影在线观看| 一本色道久久综合狠狠躁篇的优点| 久久久精品免费视频| 国产91精品高潮白浆喷水| 97精品国产97久久久久久| 69国产精品成人在线播放| 欧美性猛交xxxx乱大交蜜桃| 亚洲自拍偷拍区| 亚洲成人精品视频| 琪琪第一精品导航| 5278欧美一区二区三区| 蜜月aⅴ免费一区二区三区| 亚洲tv在线观看| 亚洲国产毛片完整版| 国产黑人绿帽在线第一区| 亚洲国产精品推荐| 欧美一区二区三区四区在线| 国产精品激情自拍| 久久久久国产精品免费| 欧美在线视频免费| 69av成年福利视频| 亚洲一区二区三区777| 日韩av在线免费播放| 欧美高清激情视频| 亚洲第一视频在线观看| 国产在线98福利播放视频| 国产亚洲福利一区| 98精品国产自产在线观看| 亚洲成人精品在线| 国产日韩在线免费| 国产91|九色| 色视频www在线播放国产成人| 亚洲人成网7777777国产|