电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

JavaScript正則表達式這幾個細節你真的知道?

瀏覽:59日期:2023-11-16 14:47:11
前言

粗淺的編寫正則表達式,是造成性能瓶頸的主要原因。如下:

var reg1 = /(A+A+)+B/; var reg2 = /AA+B/;

上述兩個正則表達式,匹配效果是一樣的,但是,效率就相差太遠了,甚至在與少量字符串匹配時,reg1就會造成你瀏覽器卡死。

不信?我們可以測試下。

首先,我們聲明一個字符串變量str,同時賦予一個包含20個A的字符串給str,采用match方法與上述reg1、reg2進行匹配測試,如下:

var str = ’AAAAAAAAAAAAAAAAAAAA’;str.match(reg1);str.match(reg2);

在瀏覽器中運行該段代碼,發現一切正常嘛。

然而,隨著,我們不斷向變量str中添加A后,重復測試,在某一刻(取決于你的瀏覽器),reg1就會讓我們的瀏覽器掛起,但,回頭看看最終的str字符串長度,卻還不到50。而,reg2卻安然無恙。

心里有一絲疑問,是什么造成了它們如此巨大的差別?以后我們在寫正則表達式時,又該如何避免防范這類問題呢?

那么,接下來,我們就有必要深入理解JavaScript正則表達式的內部執行原理了。

如果,在此你還不是很了解正則表達式,那么可以參考如下兩篇博客后,再前來,小生在此等候。

正則表達式工作原理

為了高效的使用正則表達式,理解它們的工作原理是很重要的。

具體如下:

Step1.編譯

當我們創建一個正則表達式(字面量或者RegExp對象)后,瀏覽器會檢查該正則的模板是否符合標準,然后將其轉化成內部代碼,用于執行匹配工作。

所以,如果我們將正則表達式賦予一個變量,可以避免重復執行該 ‘編譯’ 步驟。

Step2.設置開始位置

當我們使用Step1中編譯后的正則表達式時,首先它將確定從目標字符串中什么位置進行匹配。通常,是目標字符串的起始位置,或者由正則表達式的lastIndex屬性指定。

但是,當它從Step4(匹配失敗)中返回時,該位置則為匹配失敗的位置的下一個位置。

Step3.正則匹配

當經歷Step2后,正則表達式將從指定位置,從左到右,與目標字符串,逐個匹配。若,正則表達式在匹配過程中,遇到某個字元匹配不了時,它不會立即失敗,而是嘗試回溯到最近一個決策點,然后在剩余選項中選擇一個,以求繼續能匹配。

Step4.匹配結果

當經歷Step3后,發現能與正則匹配成功的子字符串,那么就匹配成功。如果,經歷了Step3后,發現沒有能與正則匹配的子字符串,那么,它將回到Step2,繼續。只有當目標字符串中的每個字符(以及最后一個字符后面的位置)都經歷了Step3后,仍沒有找到匹配項,才宣布失敗。

下面就舉個例子,使我們更透徹地明白以上4步。

如下:

var reg = /A(B|C)D/g; var str = ’ABCACD’;reg.exec(str);

① 首先,瀏覽器將解析reg正則表達式(Step1)。

② 然后,由于是首次匹配,所以確認開始位置即為字符串起始位置(Step2)。

③ 首先由正則的第一個字元A與字符串起始位置字符A匹配,成功,并在之后的位置記錄一個決策點,因為后面有分支嘛;然后由 (B|C)分支中的B選項去匹配字符串的B,發現匹配;然后再由正則下一個字元D去匹配目標字符串第三個字符C,發現不匹配,但是并沒有放棄,而是回溯,查看是否有決策點,發現有,回溯到就近一個決策點(字符串首字母A之后的那個位置上),嘗試利用第二個分支選項C去匹配字符串第二個字符B,發現不匹配,回溯,查詢是否還有其他分支選項,發現沒有,然后宣布該次失敗(Step3)。

④ 經歷Step3后,發現沒有與正則匹配的子字符串,但是,與之匹配的目標字符串的匹配位置并不是最后一個位置,所以,回到Step2,從目標字符串的下一個位置(即,字符串首字母A之后的那個位置上)開始匹配。首先由正則表達式的第一個字元A與目標字符串B匹配,不成功,又無回溯點,故而,進入Step4,判斷是否是最后一個位置,發現不是,又跳到Step2中繼續。

⑤ 就這樣一步一步,來到了目標字符串的第四個位置,首先A去與目標字符串的第三個字符A匹配,成功;接下來就是由分支(B|C),去匹配C,首先由分支中的第一個選項B去與C匹配,發現沒有成功,回溯到就近一個決策點,嘗試利用第二個分支選項C匹配,成功,緊接著D也成功了。

⑥ 匹配成功,并將lastIndex置為6。

JavaScript正則表達式這幾個細節你真的知道?

回溯

上述 “正則表達式工作原理” 一小節,Step3中的回溯我們是一筆帶過的。但是,可不要忽略了,回溯在正則中是非常重要的,如果理解得不明白,我們在編寫正則時,很容易造成回溯失控。

下面我們就來一起看看回溯在正則表達式中的運用。

正則表達式中有兩種情況,會制造回溯點:

-分支(通過|操作符)

-量詞(諸如*,+?,或者{…})

下面我們就分別舉例來看看。

分支和回溯

對于分支,詳見 ‘正則表達式工作原理’ 小節中Demo。

量詞和回溯

在量詞中,有貪婪量詞(諸如*,+)和非貪婪量詞(諸如*?,+?)之分。所以回溯形式對于它們而言也就有差別咯。我們首先寫個demo看看貪婪量詞是怎么回溯的。

Demo如下:

var reg = /w*D/g; var str = ’MonkyDorie!’;reg.exec(str);

就上述貪婪模式匹配流程如下:

提醒:正則表達式reg中w表示匹配“字母、數字或下劃線”,*這個貪婪量詞表示重復匹配零次或者多次,由于是貪婪量詞,故而它會盡可能多的匹配。

① 首先,正則中的w*與目標字符串匹配,會一直匹配到‘!’之前,即’MonkyDorie’,并且,每個匹配位置都會記錄一個決策點,便于回溯。

② 然后,由正則中的剩余字元D與字符串中!匹配,匹配失敗;但是,它并沒有放棄(因為在此之前,記錄了決策點),而是回溯到就近一個決策點(字符e的前一個位置),然后正則D與字符e匹配,匹配失敗;再回溯到就近一個決策點(字符i的前一個位置),然后正則D與字符i匹配,匹配失敗;就這樣一直回溯到字符D的前一個位置時,正則D與字符D匹配,匹配成功,并置lastIndex為6。

好了,這就是上述貪婪匹配流程。

隨后,我們將上述Demo中的正則表達式,稍微調整下,在*后面加上?,變成非貪婪模式,看看非貪婪量詞是怎么回溯的。

Demo如下:

var reg = /w*?D/g; var str = ’MonkyDorie!’;reg.exec(str);

就上述非貪婪模式匹配流程如下:

提醒:正則表達式reg中w表示匹配“字母、數字或下劃線”,*?是個非貪婪量詞,也表示重復匹配零次或者多次,但是由于是非貪婪量詞,故而它會盡可能少的匹配。

首先,正則中的w*?會選擇匹配零個字符(盡可能少的匹配),并將第一個位置(字符M的前一個位置)記錄一個決策點,繼而輪到字元D與字符串字符M匹配,匹配失敗;回溯到就近一個決策點(字符M的前一個位置),然后w*?選擇匹配一個字符M,并記錄一個回溯點(第二個字符o的前一個位置),繼而輪到字元D與字符串字符o匹配,匹配失敗;回溯到就近一個決策點(字符o的前一個位置),就這樣一步一步,當w*?選擇匹配五個字符Monky時,繼而輪到字元D與字符串字符D匹配,匹配成功,并置lastIndex為6.

上述兩Demo,對比圖如下:

JavaScript正則表達式這幾個細節你真的知道?

利用前瞻和后向引用避免回溯

正如上述 ‘回溯’ 小節中談到,重復量詞和分支會記錄決策點,引起回溯。但是,如果在實際需求中,我們不想讓它們記錄決策點呢—因為回溯太多就會導致回溯失控,影響性能,正如我們在 ‘前言’ 中看到的那樣。

一些正則表達式引擎,支持一種叫做原子組的屬性。原子組,寫作(?>…),省略號表示任意正則表達式模板。存在原子組中的正則表達式組中的任何決策點都將被丟棄。利用原子組,我們就可以在必要時,消除由重復量詞和分支記錄的決策點了。

但,在JavaScript中不支持原子組,怎么辦呢?

我們可以利用前瞻來模擬原子組,但是,前瞻在整個匹配過程中,是不消耗字符的,它只是檢查自己包含的模板是否能在當前位置匹配。然而,我們又可以利用后向引用解決此問題,如下:

(?=(pattern to make atomic))1

好了,針對 ‘利用前瞻和后向引用避免回溯’ 一節,我們寫個Demo,自我測試下:

var str = ’ABCDM’; //目標字符串 var reg1 = /w*M/; //貪婪模式 var reg2 = /(?=(w*))1M/; //貪婪模式,使用前瞻和后向引用 var reg3 = /w*?M/; //非貪婪模式 var reg4 = /(?=(w*?))M/; //非貪婪模式,使用前瞻和后向引用

對于以下匹配結果,各位看官答對否:

str.match(reg1);str.match(reg2);str.match(reg3);str.match(reg4);

來自:http://www.cnblogs.com/giggle/p/5990486.html

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 汽车整车综合环境舱_军标砂尘_盐雾试验室试验箱-无锡苏南试验设备有限公司 | 拼装地板,悬浮地板厂家,悬浮式拼装运动地板-石家庄博超地板科技有限公司 | PVC地板|PVC塑胶地板|PVC地板厂家|地板胶|防静电地板-无锡腾方装饰材料有限公司-咨询热线:4008-798-128 | 北京软件开发_软件开发公司_北京软件公司-北京宜天信达软件开发公司 | 合肥汽车充电桩_安徽充电桩_电动交流充电桩厂家_安徽科帝新能源科技有限公司 | 水冷式工业冷水机组_风冷式工业冷水机_水冷螺杆冷冻机组-深圳市普威机械设备有限公司 | 红外光谱仪维修_二手红外光谱仪_红外压片机_红外附件-天津博精仪器 | 铝镁锰板_铝镁锰合金板_铝镁锰板厂家_铝镁锰金属屋面板_安徽建科 | 压缩空气冷冻式干燥机_吸附式干燥机_吸干机_沪盛冷干机 | 海尔生物医疗四川代理商,海尔低温冰箱四川销售-成都壹科医疗器械有限公司 | 宝元数控系统|对刀仪厂家|东莞机器人控制系统|东莞安川伺服-【鑫天驰智能科技】 | 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 - 杭州标识标牌|文化墙|展厅|导视|户内外广告|发光字|灯箱|铭阳制作公司 | 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 钢格板|热镀锌钢格板|钢格栅板|钢格栅|格栅板-安平县昊泽丝网制品有限公司 | 长沙发电机-湖南发电机-柴油发电机供应厂家-长沙明邦智能科技 | OLChemim试剂-ABsciex耗材-广州市自力色谱科仪有限公司 | 骨灰存放架|骨灰盒寄存架|骨灰架厂家|智慧殡葬|公墓陵园管理系统|网上祭奠|告别厅智能化-厦门慈愿科技 | 智慧养老_居家养老_社区养老_杰佳通 | 翻斗式矿车|固定式矿车|曲轨侧卸式矿车|梭式矿车|矿车配件-山东卓力矿车生产厂家 | 数控走心机-走心机价格-双主轴走心机-宝宇百科 | 成都亚克力制品,PVC板,双色板雕刻加工,亚克力门牌,亚克力标牌,水晶字雕刻制作-零贰捌广告 | 真空搅拌机-行星搅拌机-双行星动力混合机-广州市番禺区源创化工设备厂 | 多功能真空滤油机_润滑油全自动滤油机_高效真空滤油机价格-重庆润华通驰 | 石家庄网站建设|石家庄网站制作|石家庄小程序开发|石家庄微信开发|网站建设公司|网站制作公司|微信小程序开发|手机APP开发|软件开发 | 合肥抖音SEO网站优化-网站建设-网络推广营销公司-百度爱采购-安徽企匠科技 | 筒瓦厂家-仿古瓦-寺庙-古建琉璃瓦-宜兴市古典园林建筑陶瓷厂有限公司 | 深圳诚暄fpc首页-柔性线路板,fpc柔性线路板打样生产厂家 | 山东led显示屏,山东led全彩显示屏,山东LED小间距屏,临沂全彩电子屏-山东亚泰视讯传媒有限公司 | 罗茨真空机组,立式无油往复真空泵,2BV水环真空泵-力侨真空科技 | 国资灵活用工平台_全国灵活用工平台前十名-灵活用工结算小帮手 | 碳纤维复合材料制品生产定制工厂订制厂家-凯夫拉凯芙拉碳纤维手机壳套-碳纤维雪茄盒外壳套-深圳市润大世纪新材料科技有限公司 | MOOG伺服阀维修,ATOS比例流量阀维修,伺服阀维修-上海纽顿液压设备有限公司 | 烟台金蝶财务软件,烟台网站建设,烟台网络推广| 掺铥光纤放大器-C/L波段光纤放大器-小信号光纤放大器-合肥脉锐光电技术有限公司 | 假肢-假肢价格-假肢厂家-河南假肢-郑州市力康假肢矫形器有限公司 | 雨燕360体育免费直播_雨燕360免费NBA直播_NBA篮球高清直播无插件-雨燕360体育直播 | 特种阀门-调节阀门-高温熔盐阀-镍合金截止阀-钛阀门-高温阀门-高性能蝶阀-蒙乃尔合金阀门-福建捷斯特阀门制造有限公司 | 智能垃圾箱|垃圾房|垃圾分类亭|垃圾分类箱专业生产厂家定做-宿迁市传宇环保设备有限公司 | 奶茶加盟,奶茶加盟店连锁品牌-甜啦啦官网 | 工业设计,人工智能,体验式3D展示的智能技术交流服务平台-纳金网 J.S.Bach 圣巴赫_高端背景音乐系统_官网 | 光伏支架成型设备-光伏钢边框设备-光伏设备厂家 |