乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      最火的正則表達(dá)式,學(xué)起來

       xiaoyimin 2019-09-08
      最火的正則表達(dá)式,學(xué)起來

      正則表達(dá)式是描述一組字符串特征的模式,用來匹配特定的字符串?!?——Ken Thompson

      什么是正則表達(dá)?

      正則表達(dá)式其實(shí)就是一種pattern、一種模式、一種格式、一種規(guī)則,它主要是用在文本字符串處理的時(shí)候,想要在一堆文本中找到滿足某種格式、規(guī)則的字符串。

      它起源于上個(gè)20世紀(jì)50年代科學(xué)家在數(shù)學(xué)領(lǐng)域做的一些研究工作,后來才被引入到計(jì)算機(jī)領(lǐng)域中。從它的命名我們可以知道,它是一種用來描述規(guī)則的表達(dá)式。

      比如,你要寫一個(gè)應(yīng)用, 想設(shè)定一個(gè)用戶命名的規(guī)則, 讓用戶名包含字符,數(shù)字,下劃線和連字符,以及限制字符的個(gè)數(shù),好讓名字看起來沒那么丑。那么,以下正則表達(dá)式來驗(yàn)證一個(gè)用戶名:

      最火的正則表達(dá)式,學(xué)起來

      以上的正則表達(dá)式可以接受 johndoe, jo-hndoe, john12_as. 但不匹配Jo, 因?yàn)樗舜髮懙淖帜付姨塘恕?/p>

      那么,要想學(xué)正則表達(dá)試,初學(xué)者應(yīng)該從哪些方面入手?

      這里強(qiáng)烈安利的幾個(gè)學(xué)習(xí)教程和資源:

      1.正則表達(dá)式30分鐘入門教程

      http:///tutorials/regex/regex.htm

      推薦理由:特別適合想要快速入門的同學(xué),結(jié)合實(shí)例可以讓你理解基本的原理和語法。

      2.高效入門正則表達(dá)式

      https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

      推薦理由:Github上一篇簡單的正則表達(dá)式教程,提供了十幾種語言(包括中文),這篇教程覆蓋到了你在實(shí)際應(yīng)用中99%的場景。

      3.regex101網(wǎng)站——能可視化展示正則匹配結(jié)果

      https://

      最火的正則表達(dá)式,學(xué)起來

      4.regexper網(wǎng)站——能夠直觀展示正則表達(dá)式的狀態(tài)機(jī)圖

      https://

      最火的正則表達(dá)式,學(xué)起來

      正則的進(jìn)階——從底層工作機(jī)制來理解正則表達(dá)式

      很多同學(xué)在入門某個(gè)語言或工具時(shí),總是習(xí)慣先從實(shí)例上手學(xué)習(xí),往往忽略了對語言最底層的一些原理,這里引用@小胡子哥的“進(jìn)階正則表達(dá)式”一文,來幫助你更好的熟悉和運(yùn)用正則表達(dá)式。

      注:此次引用,在原文基礎(chǔ)上做了刪減,想看完整內(nèi)容,請轉(zhuǎn)至,

      https://www.cnblogs.com/hustskyking/p/how-regular-expressions-work.html

      正則表達(dá)式的工作機(jī)制

      畫了一個(gè)草圖,簡單的說明了下正則表達(dá)式的工作原理。

      | 編譯 |
      +--------+
      |

      +----------------+
      | 設(shè)置開始位置 |←---------+
      +----------------+ ↑
      | |
      ↓ 其 |
      +----------------+ 他 |
      | 匹配 & 回溯 | 路 |
      +----------------+ 徑 |
      | |
      ↓ |
      +----------------+ |
      | 成功
      or
      失敗 |---------→+
      +----------------+

      你寫的任何一個(gè)正則直接量或者 RegExp 都會被瀏覽器編譯為一個(gè)原生代碼程序。第一次匹配是從頭個(gè)字符開始,匹配成功時(shí),他會查看是否還有其他的路徑?jīng)]有匹配到,如果有的話,回退到上一次成功匹配的位置,然后重復(fù)第二步操作,不過此時(shí)開始匹配的位置(lastIndex)是上次成功位置加 1.這樣說有點(diǎn)難以理解,下面寫了一個(gè) demo,這個(gè) demo 就是實(shí)現(xiàn)一個(gè)正則表達(dá)式的解析引擎,因?yàn)檫壿嫼托Ч谋憩F(xiàn)都太復(fù)雜了,所以只做了一個(gè)簡單的演示:

      Reg:

      /H(i|ello), barret/g

      Str:

      Lalala. Hi, barret. Hello, John

      如果上面的 demo 跑不起來,請戳這里:

      http://qianduannotes./demo/regexp/index.html

      如果要深入了解正則表達(dá)式的內(nèi)部原理,必須先理解匹配過程的一個(gè)基礎(chǔ)環(huán)節(jié)——回溯。他是驅(qū)動(dòng)正則的一個(gè)基本動(dòng)力,也是性能消耗、計(jì)算消耗的根源。

      回溯

      正則表達(dá)式中出現(xiàn)最多的是分支和量詞。上面的 demo 中可以很清楚的看到 hi 和 hello 這兩個(gè)分支,當(dāng)匹配到第一個(gè)字符 h 之后,進(jìn)入 (i | ello) 的分支選擇,首先是進(jìn)入 i 分支,當(dāng) i 分支匹配完了之后,再回到分支選擇的位置,重新選擇分支。簡單點(diǎn)說,分支就是 | 操作符帶來的多項(xiàng)選擇問題,而量詞指的是諸如 *,+?,{m,n} 之類的符號,正則表達(dá)式必須決定何時(shí)嘗試匹配更多的字符。下面結(jié)合回溯詳細(xì)說說分支和量詞。

      1.分支

      繼續(xù)分析上面那個(gè)案例。 'Lalala. Hi, barret. Hello, John'.match(/H(i|ello), barret/g),首先會查找 H 字符,在第九位找到 H 之后,正則子表達(dá)式提供了兩個(gè)選擇 (i|ello),程序會先拿到最左邊的那個(gè)分支,進(jìn)入分支后,在第十位匹配到了 i,接著匹配下一個(gè)字符,下一個(gè)字符是逗號,接著剛才的位置又匹配到了這個(gè)逗號,然后再匹配下一個(gè),依次類推,直到完整匹配到整個(gè)正則的內(nèi)容,此時(shí)程序會在 Hi,barret后面做一個(gè)標(biāo)記,表示在這里進(jìn)行了一次成功的匹配。但程序到此并沒有結(jié)束,因?yàn)楹竺婕恿艘粋€(gè)全局參數(shù),依然使用這個(gè)分支往后匹配,很顯然,到了 Hello 的時(shí)候,Hi 分支匹配不了了,于是程序會回溯到剛才我們做標(biāo)記的位置,并進(jìn)入第二個(gè)分支,從做標(biāo)記的位置重新開始匹配,依次循環(huán)。

      只要正則表達(dá)式?jīng)]有嘗試完所有的可選項(xiàng),他就會回溯到最近的決策點(diǎn)(也就是上次匹配成功的位置)。

      2.量詞

      量詞這個(gè)概念特別簡單,只是在匹配過程中有貪婪匹配和懶惰匹配兩種模式,結(jié)合回溯的概念理解稍微復(fù)雜。還是用幾個(gè)例子來說明。

      1)貪婪

      str = 'AB1111BA111BA';
      reg = /AB[sS]+BA/;
      console.log(str.match(reg));

      首先是匹配AB,遇到了 [sS]+,這是貪婪模式的匹配,他會一口吞掉后面所有的字符,也就是如果 reg 的內(nèi)容為 AB[sS]+,那后面的就不用看了,直接全部匹配。而往后看,正則后面還有B字符,所以他會先回溯到倒數(shù)第一個(gè)字符,匹配看是否為 B,顯然倒數(shù)第一個(gè)字符不是B,于是他又接著回溯,找到了B字母,找到之后就不繼續(xù)回溯了,而是往后繼續(xù)匹配,此刻匹配的是字符A,程序發(fā)現(xiàn)緊跟B后的字母確實(shí)是A,那此時(shí)匹配就結(jié)束了。如果沒有看明白,可以再讀讀下面這個(gè)圖:

      REG:
      /AB[sS]+BA/
      MATCH: A 匹配第一個(gè)字符
      AB 匹配第二個(gè)字符
      AB1111BA111BA [sS]+ 貪婪吞并所有字符
      AB1111BA111BA 回溯,匹配字符B
      AB1111BA111B 找到字符B,繼續(xù)匹配A
      AB1111BA111BA 找到字符A,匹配完成,停止匹配

      2) 懶惰(非貪婪)

      str = 'AB1111BA111BA';
      reg = /AB[sS]+?BA/;
      console.log(str.match(reg));

      與上面不同的是,reg 中多了一個(gè) ? 號,此時(shí)的匹配模式為懶惰模式,也叫做非貪婪匹配。此時(shí)的匹配流程是,先匹配AB,遇到[sS]+?,程序嘗試跳過并開始匹配后面的字符B,往后查看的時(shí)候,發(fā)現(xiàn)是數(shù)字1,不是要匹配的內(nèi)容,繼續(xù)往后匹配,知道遇到字符B,然后匹配A,發(fā)現(xiàn)緊接著B后面就有一個(gè)A,于是宣布匹配完成,停止程序。

      REG:
      /AB[sS]+BA/
      MATCH: A 匹配第一個(gè)字符
      AB 匹配第二個(gè)字符
      AB [sS]+? 非貪婪跳過并開始匹配B
      AB1 不是B,回溯,繼續(xù)匹配
      AB11 不是B,回溯,繼續(xù)匹配
      AB111 不是B,回溯,繼續(xù)匹配
      AB1111 不是B,回溯,繼續(xù)匹配
      AB1111B 找到字符B,繼續(xù)匹配A
      AB1111BA 找到字符A,匹配完成,停止匹配

      如果匹配的內(nèi)容是 AB1111BA,那貪婪和非貪婪方式的正則是等價(jià)的,但是內(nèi)部的匹配原理還是有區(qū)別的。為了高效運(yùn)用正則,必須搞清楚使用正則時(shí)會遇到那些性能消耗問題。

      逗比的程序

      //去測試下這句代碼
      'TTTTTTTT'.match(/(T+T+)+K/);
      //然后把前面的T重復(fù)次數(shù)改成30
      //P.S:小心風(fēng)扇狂轉(zhuǎn),CPU暴漲

      我們來分析下上面這段代碼,上面使用的都是貪婪模式,那么他會這樣做:

      REG: (T+T+)+K
      MATCH: ①第一個(gè)T+匹配前7個(gè)T,第二個(gè)T+匹配最后一個(gè)T,沒找到K,宣布失敗,回溯到最開始位置
      ②第一個(gè)T+匹配前6個(gè)T,第二個(gè)T+匹配最后兩個(gè)T,沒找到K,宣布失敗,回溯到最開始位置
      ③...
      ... 接著還會考慮(T+T+)+后面的 + 號,接著另一輪的嘗試。
      ⑦...
      ...

      這段程序并不會智能的去檢測字符串中是否存在 K。如果匹配失敗,他會選擇其他的匹配方式(路徑)去匹配,從而造成瘋狂的回溯和重新匹配,結(jié)果可想而知。這是回溯失控的典型例子。

      前瞻和反向引用

      1.前瞻和引用

      前瞻有兩種。一種是負(fù)向前瞻,JS中使用 (?!xxx) 來表示,他的作用是對后面要匹配的內(nèi)容做一個(gè)預(yù)判斷,如果后面的內(nèi)容是xxx,則此段內(nèi)容匹配失敗,跳過去重新開始匹配。另一種是正向前瞻,(?=xxx),匹配方式和上面相反,還有一個(gè)長的類似的是 (?:xxx),這個(gè)是匹配xxx,他是非捕獲性分組匹配,即匹配的內(nèi)容不會創(chuàng)建反向引用。具體內(nèi)容可以去文章開頭提到的文檔中查看。

      反向引用,這個(gè)在 replace 中用的比較多,在 replace 中:

      最火的正則表達(dá)式,學(xué)起來

      而在正則表達(dá)中,主要就是 ,  之類的數(shù)字引用。前瞻和反向引用使用恰當(dāng)可以大大的減少正則對資源的消耗。舉個(gè)例子來簡單說明下這幾個(gè)東西:

      問題:使用正則匹配過濾后綴名為 .css 和 .js 的文件。

      如:test.wow.js test.wow.css test.js.js等等。

      有人會立馬想到使用負(fù)向前瞻,即:

      //過濾js文件
      /(?!.+.js$).*/.exec('test.wow.js')
      //過濾js和css文件
      /(?!.+.js$|.+.css$).*/.exec('test.wow.js')
      /(?!.+.js$|.+.css$).*/.exec('test.wow.html')

      但是你自己去測試下,拿到的結(jié)果是什么。匹配非js和非css文件可以拿到正確的文件名,但是我們期望這個(gè)表達(dá)式對js和css文件的匹配結(jié)果是null,上面的表達(dá)式卻做不到。問題是什么,因?yàn)??!xxx)和(?=xxx)都會消耗字符,在做預(yù)判斷的時(shí)候把 .js 和 .css 給消耗了,所以這里我們必須使用非捕獲模式。

      /(?:(?!.+.js$|.+.css$).)*/.exec('test.wow.html');
      /(?:(?!.+.js$|.+.css$).)*/.exec('test.wow.js');

      我們來分析下這個(gè)正則:

      (?:(?!.+.js$|.+.css$).)*
      --- ---------------- -
      | | |
      +----------------------+
      ↓ |
      非捕獲,內(nèi)部只有一個(gè)占位字符
      |

      負(fù)向前瞻以.js和.css結(jié)尾的字符串

      最后一個(gè)星號是貪婪匹配,直接吞掉全部字符。

      這里講的算是有點(diǎn)復(fù)雜了,不過在稍復(fù)雜的正則中,這些都是很基礎(chǔ)的東西了,想在這方面提高的童鞋可以多研究下。

      2.原子組

      JavaScript的正則算是比較弱的,他沒有分組命名、遞歸、原子組等功能特別強(qiáng)的匹配模式,不過我們可以利用一些組合方式達(dá)到自己的目的。上面的例子中,我們實(shí)際上用正則實(shí)現(xiàn)了一個(gè)或和與的功能,上面的例子體現(xiàn)的還不是特別明顯,再寫個(gè)例子來展示下:

      str1 = '我(wo)叫(jiao)李(li)靖(jing)';
      str2 = '李(li)靖(jing)我(wo)叫(jiao)';
      reg = /(?=.*?我)(?=.*?叫)(?=.*?李)(?=.*?靖)/;
      console.log(reg.test(str1)); //true
      console.log(reg.test(str2)); //true

      不管怎么打亂順序,只要string中包含“我”,“是”,“李”,“靖”這四個(gè)字,結(jié)果都是true。

      類似(?=xxx),就相當(dāng)于一個(gè)原子組,原子組的作用就是消除回溯,只要是這種模式匹配過的地方,回溯時(shí)都不會到這里和他之前的地方。上面的程序 'TTTTTTTT'.match(/(T+T+)+K/);可以通過原子組的方式處理:

      'TTTTTTTT'.match(/(?=(T+T+))+K/);

      如此便能徹底消除回溯失控問題。

      - 完 -


      與其他程序設(shè)計(jì)語言一樣,學(xué)習(xí)正則表達(dá)式的關(guān)鍵是實(shí)踐,實(shí)踐,再實(shí)踐。 ——本·福塔(Ben Forta)

      最火的正則表達(dá)式,學(xué)起來

      [美] 本·福塔(Ben Forta)著 門佳 楊濤 等 (譯)

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多