關於正則表達式,和不少前輩聊起這個知識點時,他們的反饋都比聊其餘技術謙遜,而和不少剛入門的程序員討論時甚至會有以爲你看不起他。html
的確,正則表達式從一般的應用來看,的確不難,好比電話,郵箱等驗證。語法,邏輯都算不上覆雜,我以前也認爲正則表達式也算不上什麼高大上的技術。程序員
可是,改變我見解的是,有一次有個前輩給我出了一個題:面試
將一串數字從後向前每隔三位打點,例如「100000000000000」;正則表達式
var str = "100000000000000"; var reg = /(\B)(?=(\d{3})+$)/g; console.log(str.replace(reg,"."));
//輸出結果:100.000.000.000.000
後來他跟我說,這個題是百度有一年校招的最後一個題,20分。編程
有人會說,這個並非惟一的解法。數組
不錯,這的確不是,可是隻有這個解法當年百度給了滿分,其餘解法就算答案正確,基本上都只給了3~5分。瀏覽器
或許這個事情告訴了咱們,結果並非編程的「結果」,程序的核心價值應該是效率。ruby
正則表達式在基礎應用領域的確不難,可是在實際解決問題的時候能用正則表達式化繁爲簡的不見得有多少人能作獲得。編程語言
我對正則表達式也只能說是作到了解,寫這篇博客的緣由是但願能與你們互動學習深刻的掌握正則表達式,有什麼關於正則表達式的問題你們能夠在評論區留言交流,也但願你們多多分享關於正則表達式的實際應用,同時,我也用過這篇文章總結一些關於正則表達式的基礎知識點,方便你們查閱和學習交流,有什麼地方總結的不正確的地方還但願你們多多指正。ide
正則表達式的基礎知識點:
1.轉義字符
2.元字符
3.區間——方括號[]
4.重複限定符(量詞)
5.邊界與屬性
6.分組與子表達式及反向引用
7.條件或
8.捕獲與非捕獲
9.零寬斷言
10.貪婪與非貪婪
以上就是正則表達式的全部知識點,內容之少,可是其份量在編程領域之重不言而喻,全部的編程語言都有正則表達式就說明了這一點。
個人總結沒有根據知識點的難易程度來排序,在寫這篇博客以前我也參考了別人的博客,甚至我開始學習的時候很大程度也是靠讀博客,可是我總感受有些方式並非很合適,大部分的正則表達式入門博客都是基於難易程度排序來說,並且還拆分的很細,有的之間有很大關聯的知識點被拆分,中間還隔了幾個知識點,理解起來費勁。
這麼來說吧,我看過好幾本研究關於記憶和學習的書,它們都有一個共通點,就是講究知識的關聯性,甚至在一些記憶大師的理論裏,他們爲了強記一些沒有關聯的信息時都會特地採用一些其餘關聯性的將其關聯起來,來增強記憶,好比很出名的《記憶宮殿》,好了,有點扯遠了,我只想告訴你們我這樣的總結安排會更加適合理解學習。
1.轉義字符:「\」
其實轉義字符算不上徹底的正則表達式的知識點。
將他放到這裏來說,並且還放到第一個來說,是考慮到方便剛剛學習正則表達式的同窗理解後面的知識點。
通俗的解釋轉義字符就是,經過「\」來表達咱們不能按照正常字符表達方式的字符。
示例,若是在一個字符串中有一個雙引號字符:
var mark= "ab\"cd"; console.log(mark); //輸出ab"cd
反斜槓「\」在字符串中的做用就是,將它後面的字符變成該字符串的文本,而自己不做爲字符串的實際字符。
轉義字符,也就是反斜槓"\"在程序邏輯上,做用是清除字符自己自帶的語法含義。上一個示例就是利用反斜槓清楚了雙引號的語法含義。
//1.自己不做爲字符串的實際字符 var mark = "ab\cd"; console.log(mark); //輸出結果:abcd //2.若是反斜槓是字符串的一個字符? var backslash ="\\";
console.log(backslash); //輸出結果:\ //3.一個字符串中包含了一個反斜槓「\」,剛好後面還跟了一個n或者r又或者0 //會出現什麼狀況,怎麼解決 var n = "ab\ncd"; //輸出結果:ab // cd var nn = "ab\\ncd"; //輸出結果:ab\ncd var r = "ab\rcd"; //輸出結果:abcd var rr = "ab\\rcd"; //輸出結果:ab\rcd var zero = "ab\0cd"; //輸出結果:ab cd var zeros = "ab\\0cd"; //輸出結果:ab\0cd;
轉義字符還有一個比較經常使用的實際開發應用,就是咱們遇到一個結構比較複雜的字符,
可是字符串在一般的語法中不能換行,這時咱們就能夠採用轉義字符來解決。
var inhtml = "\ <div>XXXXX</div>\ <ul>\ <li>XXX</li>\ <li>XXX</li>\ </ul>\ ";
關於轉義字符暫時就解釋到這裏,很簡單的一個知識點,算是一個前期鋪墊吧。
2.元字符
元字符 | 說明 |
. | 匹配除換行(\n)和回車符(\r)之外的任何字符 |
^ | 匹配字符串的開始位置。(邊界部分詳細介紹) |
$ | 匹配字符串的結束位置。(邊界部分詳細介紹) |
\w | 匹配單詞字符,即0-9A-z_;(區間部分詳細介紹) |
\W | 匹配非單詞字符,即除了\w之外的任何字符(區間部分詳細介紹) |
\d | 匹配數字,即0-9;(區間部分詳細介紹) |
\D | 匹配非數字字符,即除了\d的任何字符(區間部分詳細介紹) |
\s | 匹配空白字符 。(區間部分詳細介紹) |
\S | 匹配非空白字符。(區間部分詳細介紹) |
\b | 匹配單詞邊界, 即單詞的先後兩個位置。(邊界部分詳細介紹) |
\B | 匹配非單詞邊界,即不是單詞的先後兩個位置。(邊界部分詳細介紹) |
\0 | 匹配null,在字符串中採用轉義形式,\0實現的是一個空格的效果。(根據轉義字符,參考\n的詳細說明理解) |
\n | 匹配換行字符。 在字符串中出現了\n如:var str = "ab\ncd";匹配字符串str的正則能夠寫成/ab\ncd/或者/\w\w\n\w\w/; 若是經過console.log輸出的字符串是:ab\ncd,咱們能夠經過轉義字符推導出字符串爲"ab\\ncd";相匹配的字符串也要寫成/ab\\ncd/; |
\f | 匹配換頁符。(根據轉義字符,參考\n的詳細說明理解) |
\r | 匹配回車符。(根據轉義字符,參考\n的詳細說明理解) |
\t | 匹配製表符。(根據轉義字符,參考\n的詳細說明理解);(\t同等於在編輯文本時輸入TAB鍵,可是在字符串中輸入TAB會被編譯成空格,要想在字符串中得到實際的TBA鍵入同樣的效果就是在字符串中寫入\t,因此就有了這個反向字符) |
\v | 匹配垂直製表符。(根據轉義字符,參考\n的詳細說明理解) |
\XXX | 匹配以八進制數XXX規定的字符 。 |
\Xdd | 匹配以十六進制數dd規定的字符 。 |
\uXXXX | 匹配以十六進制數XXXX規定的Unicode字符。 |
3.區間——方括號[]
正則表達式提供一個元字符「方括號」(也一般稱「中括號」)來表示一個字符的取值範圍。
限定一個字符爲0~9能夠寫成[0-9]; -->即爲數字字符,也能夠用「\d」表示。
限定一個字符爲a~z,即爲小寫字母能夠寫成[a-z];
限定一個字符爲A~Z,即爲大寫字母能夠寫成[A-Z];
因此若是一個字符爲任意字母和數字能夠表示爲[a-zA-Z0-9]。
限定一個字符是指定的幾個字符中的任意一個能夠寫成[a%M],即表示這個字符只能是「a」,「%」,"M"其中的一個。
也能夠經過[^]的方式反向取值,即表示除了羅列的字符之外的任意字符。
假設一個字符不是"a","b","c"的任意字符能夠表示成[^abc]。
在前面的元字符中,不少都擁有相似功能,其實際也是區間的一種表達形式,下面我就用區間的形式解析出來,供你們參考。
1 \w === [0-9A-z_]; 2 \W === [^\w]; 3 \d === [0-9]; 4 \D === [^\d]; 5 \s === [\t\n\r\v\f]; 6 \S === [^\s];
4.重複限定符(量詞)
語法 | 說明 |
* | 重複零次或更屢次 |
+ | 重複一次或更屢次 |
? | 重複零次或一次 |
{n} | 重複n次 |
{n,} | 重複n次或更屢次 |
{n,m} | 重複n到m次 |
在沒有重複限定符的狀況下,正則表達式就是一個累贅,因此在前面一直沒有真正意義的寫過示例演示。
有了重複限定符以後,應用一些實例來理解正則表達式:
1 //匹配11位數的手機號碼 2 //不使用重複限定符的狀況下 3 /^1\d\d\d\d\d\d\d\d\d\d$/ 4 //使用重複限定符 5 /^1\d{10}$/ 6 7 //匹配八位數的QQ號碼 8 /^\d{10}$/ 9 10 //匹配銀行卡號14至18位的數字 11 /^\d{14,18}$/ 12 13 //匹配任意長度的單詞 14 /\b\w+\b/
5.邊界與屬性
在解析邊界與屬性以前,咱們先要了解一下正則表達式的匹配原則。
正則表達式表明的是一個字符串中的某個片斷的規律,
當使用正則表達式的方法對一個特定的字符進行匹配的時候,
正則表達式會對字符的每一個字符從前日後逐個匹配。
屬性 | 說明 |
g | 全局匹配 |
i | 忽略字母大小寫 |
m | 多行匹配 |
關於g的全局匹配邏輯我以爲用下面一段代碼更容易解釋,也更清晰明瞭。
1 var str = "a1b2c3d"; 2 var reg = /\d/; 3 //匹配到的結果是:1 4 var reg1 = /\w/g; 5 //匹配到的結果是:1,2.3 6 7 var str1 = "a123b456c789d"; 8 var reg2 = /\w+/; 9 //匹配結果是:123; 10 var reg3 = /\w+/g; 11 //匹配到的結果是:123,456,789;
以上的代碼說明了g屬性可使字符串中,符合條件的全部片斷匹配出來。
這時候有的同窗就會說23,56,89也符合\d+的形式,是的,從正則表達式來說的確符合條件,
可是,匹配原則不會從新匹配已經被匹配的字符。
接下來解釋,關於邊界內容,先看如下示例:
字符串12345678符合/\d{8}/,若是使用這樣的一個正則表達式來驗證8位數的字符串是否合理呢?
若是出現字符串123456789,/\d{8}/也符合匹配條件,可是他卻不是8位數的字符串。
這時候咱們就須要引入邊界來解決這個問題:
var str1 = "12345678"; var str2 = "123456789"; var reg = /^\d{8}$/; //字符串str1能被成功匹配 //還可使用下面的正則表達式進行匹配驗證 var reg3 = /\b\d{8}\b/ //實質上\b是表示一連串符合\w的字符的先後位置 //元字符中\w的官方說明就是單詞字符,其中包括了[A-z0-9_] //因此咱們能夠經過如下正則表達式來獲取一段英文的全部單詞 var reg4 = /\b\w+\b/g;
以上代碼說明了:^ 表示字符串的開始位置;$ 表示字符串的結束位置; \b表示單詞的開始或結束位置。
關於邊界就還剩下兩個問題:
a.^在正則表達式中存在多重含義:一種是在區間內做爲開頭表示非的意思,在邊界上表示字符串的起始位置。
b.非單詞邊界指的是什麼?
//有以下字符串 var str = "this is my phone"; //需求:判斷這段英文中有沒有單詞中包含is,但不是獨立的一個is單詞。 var reg = /\Bis/g; //非單詞邊界意思就是否是單詞的開頭和結尾處
關於屬性,還有"i"和"m"分別具有什麼功能?
//有需求:在一段英文中匹配到is這個單詞,而且忽略大小寫 var reg = /\b[iI][sS]\b/g; //若採用i屬性忽略大小寫就能夠寫成 var regi = /\bis\b/ig; //若是有這樣一串字符串 var str = "ab\nacd\naef"; var regs = /^a\w+/g; //匹配結果是:ab var regm = /^a\w+/gm;
//匹配結果是:ab,acd,cef;
i屬性忽略字母大小寫就再也不多作解釋了。
m屬性可能會有不少朋友不是很清楚,
在這裏若是要嚴格的理解"^"這個符號就是一行字符串開頭的意思。
因此,經過m屬性匹配上面示例的結果就會有三個。
(其實主要的問題是在於對「^」符號的的理解誤區,一般咱們在正則表達式內,這個符號在邊界的意義都理解爲字符串的開頭,其實否則,準確的說是一行字符串的開頭。)
6.分組與子表達式及反向引用
關於分組對於表達式相當重要,後面的幾個知識點都會圍繞分組展開。
若是隻是分組,它自己是一個很是簡單易懂的知識點:
1 var str = "abcdef"; 2 //用正則表達式分組的形式按每組兩個字符進行匹配 3 var reg = /(ab)(cd)(ef)/;
以上示例中的正則表達式實際的匹配結果與/abcdef/沒有任何區別,都是將整個str字符匹配出來。
可是,自己看似沒有任何意義反而成就了他的價值,就想HTML的div標籤同樣,實際沒有任何特性的容器標籤卻成了HTML中最重要的一個標籤。
不扯遠了,回到正則分組的自己,正則表達式有了分組,就像碳元素在高溫環境下有了氧氣;
由於分組,產生了子表達式:
在上面的示例中,正則表達式中的分組產生了三個子表達式:(ab),(cd),(ef)
//子表達式再上一個示例中沒有什麼價值 //若是有如下字符串(大駝峯命名規則) var str = "AbafdcDfdefGhfdi"; //若是須要用正則表達式來驗證的話,正則能夠寫成 var reg = /^([A-Z][a-z]+)+$/
驗證大駝峯命名法的字符串,就是應用了分組的子表達式重複匹配來簡化代碼。
從這裏開始,感受正則表達式要走上風騷路線了,接下來看看反向引用
1 //查找如下字符串中連續重複出現的單詞,而且忽略大小寫 2 var str = "Is is the cost of of gasoline going up up?"; 3 var reg = /(\b[a-z]+\b) \1/ig; 4 5 //匹配連續出現的字母組合的字符串片斷 6 var str1 = "abcabcabc"; 7 var reg1 = /^(\w{2})\1+$/; 8 9 //匹配一下形式的字母組合的正則表達式 10 var str2 = "aabb"; 11 var reg2 = /(\w)\1(\w)\2/g;
剛接觸反向引用事,看到上面的示例,我想每一個人都會有這樣的疑問:\1和\2是什麼意思?
這裏的1和2所表示的就是第一個子表達式和第二個子表達式經過匹配獲取到的對應的「字符串片斷」的引用。
以最後一個示例爲例,匹配過程能夠將其拆分紅兩個步驟:
第一個步驟是子表達式匹配得到匹配結果:/(\w)a(\w)b/; ——>子表達式優先匹配,獲取匹配到的具體字符串片斷,並傳給引用本身的引用。
第二個步驟就是將第一個步驟獲取到的具體的表達式與字符串匹配。
(提供一個記憶理解的方法:反向引用這個技術名稱別隻看着高大上,其實本質上已經經過語義化向咱們傳遞了不少信息,數字n表示第幾個子表達式,即爲引用值。
而反向即爲將數字本來在正則表達式中表示的是一個字符,經過轉義字符反轉爲一個引用對象;反向還有的第二層含義就是數字引用的不是子表達式的自己,
而是經過子表達式匹配的對應字符串片斷。)
7.條件或 —— |
條件或其實與一般編程中的雙豎線「||」是一個意思,只不過在正則表達式中只要寫一個豎線「|」。
示例說明:
//咱們的手機號碼不一樣的運營商,開頭的三個數字都不一樣,並且每一個運營商下都有好幾個不一樣的開頭數字。 //例如聯通旗下有:130/131/132/155/156/185/186/145/176 //若是業務需求是要匹配全部的聯通手機號碼。請看下列代碼: var reg = /^(130|131|132|155|156|185|186|145|176)\d{8}$/;
很簡單的一個知識點,可是要藉助分組來表示,因此就留到這裏來說了。
8.捕獲與非捕獲
在解析捕獲與非捕獲前,我想先在這裏添加一些內容,幫助更好的理解這一部分知識點。
就是基於JavaScript關於正則表達式的一個操做方法:
JavaScript的RegExp對象的exec()方法:
不過在這裏暫時不對方法的全部內容進行解析,只解析部分與捕獲相關的內容。
1 //仍是延用分組的示例,畢竟捕獲是基於分組的 2 var str = "abcdef"; 3 //用正則表達式分組的形式按每組兩個字符進行匹配 4 var reg = /(ab)(cd)(ef)/; 5 //使用exec()方法獲取到匹配結果 6 console.log(reg.exec(str)); 7 //匹配結果是:["abcdef", "ab", "cd", "ef", index: 0, input: "abcdef", groups: undefined]
在這個匹配結果裏,類數組的第一個元素就是正則表達式匹配到的內容。
第二個元素:「ab」是第一個子表達式的匹配結果
第三個元素:「cd」是第二個子表達式的匹配結果
第四個元素:「ef」是第三個子表達式的匹配結果
先不討論,繼續看如下示例
//在上面的示例基礎上,正則表達式修改爲 var reg = /(ab)(?:cd)(ef)/; //使用exec()方法獲取到匹配結果 console.log(reg.exec(str)); //匹配的結果是:["abcdef", "ab", "ef", index: 0, input: "abcdef", groups: undefined]
這回的匹配結果發生了一個小小的變化。
第二個子表達式的前面添加了「?:」,讓匹配結果中沒有出現第二個子表達式的對應元素;
可是整個正則匹配結果,也就是類數組的第一個元素沒有受到影響,仍是和上一個示例的匹配結果徹底一致。
以上示例經過exec()方法展示出來的結果,就是捕獲與非捕獲的結果。
捕獲是正則表達式分組的一個特性,他會將每一個分組即子表達式匹配到的結果提取出來,即爲捕獲。
捕獲產生了數據組,咱們就能夠經過反向引用的方式在正則表達式中,經過捕獲數據組的「」鍵「」引用捕獲值。(反向引用實現的底層原理)
而非捕獲就是在子表達式前面加上了「?:」,表示該組爲非捕獲組,非捕獲組匹配的結果不會被提取,可是該組的匹配功能依然存在。
看到以上的總結,你們可能視乎懂了捕獲與非捕獲,可是仍是不知道捕獲與非捕獲有什麼用途。
請看如下示例:
var str = "aa11aa11aa11"; var reg1 = /((aa)(11))+/; var reg2 = /(?:(aa)(11))+/; console.log(reg1.exec(str)); //匹配結果是:["aa11aa11aa11", "aa11", "aa", "11", index: 0, input: "aa11aa11aa11", groups: undefined] console.log(reg2.exec(str)); //匹配結果是:["aa11aa11aa11", "aa", "11", index: 0, input: "aa11aa11aa11", groups: undefined]
上面的示例所展現的內容,能夠看到一個區別,
而偏偏是一個區別能夠幫助咱們解決一個巨大的困擾。
在前面的總結中咱們能夠知道有了捕獲數據能夠被引用,
可是在上面的這個示例的時候,當分組被嵌套的時候,
「鍵」所對應的「值」就不會那麼好對應了,好比上面示例的第一個匹配結果,若是在正則表達式中須要引用(aa)匹配的值,就是「\2」;
非捕獲也就是讓被標註爲非捕獲組的對應匹配值不會出如今捕獲數據內。
不少朋友以爲捕獲很難,我並不以爲,寫了這麼一大段我本身反而以爲累贅,看着就累,若是能夠我以爲有下面一句話就能夠了。
被標註非捕獲的分組,所匹配的字符串片斷不能反向引用。
9.零寬斷言
零寬與斷言這一部分,真的不難好嗎?
有多少人困在這一部分,點贊舉手,我來告訴大家如何不難。
我以爲這部分,難度不在知識點,而是在知識點的專業名稱,我看到的和聽到了就不下三種。
因此我想先不解釋理論和原理,直接看看怎麼用,而後再解釋原理。
1 //若有需求:找到一個的開桑塔納的車主(且名字爲三個字) 2 var str11 = "李小明開桑塔納"; 3 var str12 = "王小明開福克斯"; 4 var reg1 = /^.{3}(?=開桑塔納)/; 5 console.log(str11.match(reg1)); 6 console.log(str12.match(reg1)); 7 //輸出結果:[李小明] 8 //輸出結果:null 9 10 11 //有須要如:查找電話號碼,電話號碼前面的字符是「電話:」,但不能匹配該字段。 12 var str21 = "電話:15177775555"; 13 var str22 = "金額:11111111111"; 14 var reg2 = /(?<=電話:)1\d{10}/g; 15 console.log(str21.match(reg2)); 16 console.log(str22.match(reg2)); 17 //輸出結果:[15177775555] 18 //輸出結果:null 19 20 //全局忽略大小寫,查找後買沒有all的is 21 var str3 = "Is this all there is"; 22 var reg3 = /is(?! all)/gi; 23 console.log(str3.match(reg3)); 24 //輸出結果:["Is", "is"] 25 26 27 //假設有如下兩個字符串,須要用正則判斷不「美國芯片」 28 var str41 = "美國芯片"; 29 var str42 = "中國芯片"; 30 var reg4 = /(?<!美國)芯片/; 31 console.log(str41.match(reg4)); 32 console.log(str42.match(reg4)); 33 //輸出結果:null 34 //輸出結果:["芯片", index: 2, input: "中國芯片", groups: undefined]
我如今能夠告訴你,零寬斷言已經學完了,可能出現的四個特例在上面的實例中所有展現出來了。
下面給你們介紹原理、特例(?=,?!,?<=,?<!)、及專業名詞。
在解釋原理前,咱們先來看看特例:
xx(?=exp)表示查找xx,這個xx的後面必須跟着exp
xx(?!exp)表示查找xx,這個xx的後面不能跟着exp
(?<=exp)xx表示查找xx,這個xx的前面必須是exp
(?<!exp)xx表示查找xx,這個xx的前面不能出現exp
零寬與斷言的含義(即這兩個專業名詞描述了什麼東西)
斷言:所謂斷言,與通俗的表達是一回事,表示確定什麼的意思。這正則表達式內,斷言就是表達「xx」字符串片斷的先後確定會出現什麼樣的狀況。
零寬:這個名稱也是語義化的一個專業名稱,你們發現全部四個特例都是以分組的方式寫在正則表達式內,
可是這樣的分組不執行正則匹配,它的做用只是一個判斷條件。也就是它不佔用匹配的字符片斷。
說了這麼多,出一個小小的題,你們一塊兒熟悉一下零寬斷言:用正則表達式匹配獲取一個網頁的標題名稱。
1 var str = "<title>他鄉踏雪的主頁</title>"; 2 var reg = /(?<=<title>).*(?=<\/title>)/g; 3 console.log(str.match(reg));
接下來,就來解決名稱的問題吧。這個問題就是個奇葩!
正則表達式零寬斷言的特例 | 第一類名稱(參考百度百科) | 第二類命名 |
XX(?=exp) | 零寬度正預測先行斷言 | 正向前瞻 |
XX(?!exp) | 零寬度負預測先行斷言 | 負向前瞻 |
(?<=exp)xx | 零寬度正回顧後發斷言 | 正向後瞻 |
(?<!exp)xx | 零寬度負回顧後發斷言 | 負向後瞻 |
最後關於零寬斷言,其實我也還有點疑惑,在不少博客和教程上見過說,js的正則不能用(?<=)和(?<!),我使用的是Chrome瀏覽器:版本 69.0.3452.0作的測試,沒毛病,還望路過的大神指點一下,是否是真的有那個瀏覽器不兼容這兩個零寬斷言的特例。
10.貪婪與非貪婪
這知識點幾乎是正則表達式最冷門的一個,由於在平常開發中很是少用,特性自己也不太好駕馭。
可是別小看它,千萬別小看,我最後會給一個示例給你們看,大家就會明白。
那到底什麼是貪婪模式和非貪婪模式呢?先看一個示例:
1 var str = "abcaxcd"; 2 var reg = /ab.*c/; 3 var reg1 = /ab.*?c/; 4 console.log(str.match(reg)); 5 //匹配到的結果是:abcaxcd 6 console.log(str.match(reg1)); 7 //匹配到的結果是:abc
看到上面的示例後,兩個正則表達式的差異就是在量詞星號*的後面多了一個問號?
這也就是貪婪與非貪婪的區別:
貪婪模式就是僅量詞的最大值去匹配最多的相符的字符。
非貪婪模式就是無論量詞的最大範圍有多大,只要是非貪婪模式就儘量的少匹配字符。
可是,有一種例外:
var str = "abcaxcd"; var reg = /ab.*?d/; console.log(str.match(reg)); //匹配結果是:abcaxcd
這種例外就是,當一個執行非貪婪模式匹配的字符後面,有一個匹配字符能夠字符,貪婪模式會延伸,直到後面的字符被匹配到的前面結束匹配。
記住,必定是後面的字符有可能被匹配到的狀況下,不然匹配結果爲null
接下來乾點正事,關於貪婪模式與非貪婪模式的語法是應該正式的介紹一下了:
貪婪模式的量詞表示 | 非貪婪模式的量詞表示 |
n* | n*? |
n+ | n+? |
n? | n?? |
n{x} | n{x} ? |
n{x,} | n{x,} ? |
n{x,y} | n{x,y} ? |
最後對線承諾,放大招,貪婪和非貪婪組合斷言特性,看看如下示例:
1 //有需求時:保留一下HTML文檔中的innerHTML和hr標籤 2 var str = "<p><a href='http://www.cnblogs.com/rubylouvre/'>Ruby Louvre</a></p><hr/><p>by <em>司徒正美</em></p>"; 3 var reg = /<(?!hr)(?:.|\s)*?>/ig; 4 console.log(str.replace(reg,"")); 5 //打印結果是:Ruby Louvre<hr/>by 司徒正美
關於正則表達式的基礎內容總結就在以上所有內容了,
後續還會有關於js正則應用的方法的具體解析,
而後就是具體的正則表達式通式的概括,
還有正則表達式的面試習題,還但願你們能多多提供一些資源。