最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一次JavaScript正則的詭異經(jīng)歷記錄

 更新時(shí)間:2022年04月21日 09:27:26   作者:Lam  
正則表達(dá)式是用于匹配字符串中字符組合的模式,下面這篇文章主要給大家介紹了一次JavaScript正則的詭異經(jīng)歷記錄,文中通過實(shí)例介紹的非常詳細(xì),需要的朋友可以參考下

事情是這樣的,最近在寫一個(gè)Node功能的時(shí)候,遇到了一個(gè)正則的問題,覺得挺有意思的,就記錄一下經(jīng)歷和最終問題原因,希望也能幫助到同樣遇到的同學(xué)。

背景

我有一個(gè)Node服務(wù),希望對訪問進(jìn)來的請求進(jìn)行標(biāo)記,如果請求進(jìn)來的path是我定義的路由,那么將標(biāo)記一個(gè)REQ,否則標(biāo)記一個(gè)IVL,用于對于整個(gè)服務(wù)的日志記錄進(jìn)行輸出。那么我通過服務(wù)啟動時(shí),根據(jù)定義的路由,生成一個(gè)RouterMap,通過訪問進(jìn)入時(shí),判斷path是否命中RouterMap來判斷是否預(yù)期訪問。

大概的代碼如下:

export function getSourceMak(
? routerMap: AppRouterMap[],
? req: http.IncomingMessage,
): SourceMark.REQ | SourceMark.IVL | SourceMark.TST {
? const { url, method, headers } = req;
? const pathname = url.split('?')[0];
? const userAgent = headers['user-agent'];
? // 安全掃描
? if (userAgent?.includes('TST(Tencent') && userAgent.includes('Team)')) {
? ? return SourceMark.TST;
? }
? for (const item of routerMap) {
? ? const { reg } = item;
? ? if (reg.test(pathname) && item.method === method.toLocaleLowerCase()) {
? ? ? return SourceMark.REQ;
? ? }
? }
? return SourceMark.IVL;
}?

因?yàn)樯婕暗揭恍﹦討B(tài)路由的原因,不能直接通過path進(jìn)行相等判斷,需要對相應(yīng)的路由規(guī)則生成一個(gè)對應(yīng)的正則表達(dá)式,并且在服務(wù)啟動時(shí)生成,保存在內(nèi)存中進(jìn)行復(fù)用。

生成正常代碼如下:

export function createRouterRegexp(url) {
  const urlBlock = url.split('/');
  const regBlock = urlBlock.map((block) => {
    if (block[0] === ':') {
      return '((?!/).)*';
    }
    return block;
  });
  return new RegExp(`^${regBlock.join('/')}$`, 'ig');
}

問題

然后在進(jìn)行調(diào)試的時(shí)候發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象,假設(shè)我有一個(gè)路由為GET /cats/find的路由,通過打點(diǎn)發(fā)現(xiàn)對應(yīng)的正則表達(dá)式,/^\/cats\/find$/gi對/cats/find進(jìn)行匹配的時(shí)候,第一次為true,第二次為false,第三次為true,第四次為false,以此類推。

經(jīng)過反復(fù)驗(yàn)證,node代碼并沒有存在問題,正則表達(dá)式也沒有問題,那么我在瀏覽器中嘗試復(fù)現(xiàn)一下,也是得出同樣的問題。至此我很確定,一定是有一些正則相關(guān)的坑是我以前沒有注意到。于是我反查了一下JavaScript的文檔,終于被我找到原因。

原因

通過查找MDN正則相關(guān)的文檔,被查到以下說明

"nolink">當(dāng)設(shè)置全局標(biāo)志的正則使用test()

如果正則表達(dá)式設(shè)置了全局標(biāo)志,test() 的執(zhí)行會改變正則表達(dá)式 lastIndex屬性。連續(xù)的執(zhí)行test()方法,后續(xù)的執(zhí)行將會從 lastIndex 處開始匹配字符串,(exec() 同樣改變正則本身的 lastIndex屬性值).

下面的實(shí)例表現(xiàn)了這種行為:

var regex = /foo/g; 
// regex.lastIndex is at 0 
regex.test('foo'); // true 
// regex.lastIndex is now at 3 
regex.test('foo'); // false

RegExp.prototype.test() - JavaScript | MDN

這不就是我遇到的問題嗎?

通過文檔說明得知,當(dāng)我們正則表達(dá)式帶有g(shù)標(biāo)識進(jìn)行全局匹配時(shí),匹配成功后,regex實(shí)例中會有一個(gè)lastIndex屬性去記錄本次命中正則的最后一位的下標(biāo)+1,用于在下一次調(diào)用test的時(shí)候,從lastIndex開始進(jìn)行匹配。 以前我沒有遇到過大概率是因?yàn)橐韵略颍?/p>

每次進(jìn)行正則校驗(yàn)時(shí),都重新生成正則實(shí)例:/^\/cats\/find$/gi.test('/cats/find') 。

但是因?yàn)檫@次我將正則實(shí)例保存,并反復(fù)使用。從而導(dǎo)致問題。

并且通過驗(yàn)證得出,當(dāng)匹配成功后,lastIndex會記錄下一次開始的位置,但是當(dāng)匹配失敗,lastIndex會歸零從頭開始。

至此這一次被坑經(jīng)歷耗時(shí)60分鐘左右,耽誤了吃飯最佳時(shí)間,導(dǎo)致飯?zhí)貌硕伎鞗]有。但是同時(shí)也收獲到JavaScript在正則上一個(gè)容易被忽略的坑。好像也不虧。

總結(jié)

到此這篇關(guān)于一次JavaScript正則的詭異經(jīng)歷記錄的文章就介紹到這了,更多相關(guān)JavaScript正則經(jīng)歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

元阳县| 忻城县| 雅江县| 永修县| 临安市| 鸡泽县| 吴江市| 景德镇市| 措美县| 新巴尔虎左旗| 岑溪市| 鹿邑县| 马鞍山市| 金山区| 梁河县| 布尔津县| 乐清市| 道真| 页游| 海丰县| 望城县| 澄迈县| 藁城市| 阳新县| 台东市| 楚雄市| 东阳市| 古丈县| 辽宁省| 理塘县| 裕民县| 舞钢市| 高淳县| 湘阴县| 合水县| 炎陵县| 仪陇县| 麟游县| 龙岩市| 星子县| 江达县|