深入淺出的javascript的正規表示式學習教程

發表於2015-12-11

深入淺出的javascript的正規表示式學習教程

閱讀目錄

瞭解正規表示式的方法

RegExp物件表示正規表示式,它是對字串執行模式匹配的工具;

 正規表示式的基本語法如下2種:

  1. 直接量語法:

         /pattern/attributes;

     2. 建立RegExp物件的語法

         new RegExp(pattern,attributes);

引數:引數pattern是一個字串,指定了正規表示式的模式;引數attributes是一個可選的引數,包含屬性 g,i,m,分別使用與全域性匹配,不區分大小寫匹配,多行匹配;

@return 返回值:一個新的RegExp物件,具有指定的模式和標誌;

    1-1. 支援正規表示式的String物件的方法

       1. search()方法;該方法用於檢索字串中指定的子字串,或檢索與正 則表示式相匹配的字串。

       基本語法:stringObject.search(regexp);

      @param 引數regexp可以需要在stringObject中檢索的字串,也可以 是需要檢索的RegExp物件。

      @return(返回值) stringObject中第一個與regexp物件相匹配的子串的起 始位置。如果沒有找到任何匹配的子串,則返回-1;

    注意:search()方法不執行全域性匹配,它將忽略標誌g,同時它也沒有regexp物件的lastIndex的屬性,且總是從字串開始位置進行查詢,總是返回的是stringObject匹配的第一個位置。

測試demo如下:

    2. match()方法;該方法用於在字串內檢索指定的值,或找到一個或者多個正規表示式的匹配。該方法類似於indexOf()或者lastIndexOf(); 但是它返回的是指定的值,而不是字串的位置;

基本語法:

   stringObject.match(searchValue) 或者stringObject.match(regexp)

   @param(引數) 

   searchValue 需要檢索字串的值;

    regexp: 需要匹配模式的RegExp物件;

   @return(返回值) 存放匹配成功的陣列; 它可以全域性匹配模式,全域性匹配的話,它返回的是一個陣列。如果沒有找到任何的一個匹配,那麼它將返回的是null;返回的陣列內有三個元素,第一個元素的存放的是匹配的文字,還有二個物件屬性;index屬性表明的是匹配文字的起始字元在stringObject中的位置;input屬性宣告的是對stringObject物件的引用;

如下測試程式碼:

3. replace()方法:該方法用於在字串中使用一些字元替換另一些字元,或者替換一個與正規表示式匹配的子字串;

    基本語法:stringObject.replace(regexp/substr,replacement);

   @param(引數) 

    regexp/substr; 字串或者需要替換模式的RegExp物件。

    replacement:一個字串的值,被替換的文字或者生成替換文字的函式。

   @return(返回值)  返回替換後的新字串

   注意:字串的stringObject的replace()方法執行的是查詢和替換操作,替換的模式有2種,既可以是字串,也可以是正則匹配模式,如果是正則匹配模式的話,那麼它可以加修飾符g,代表全域性替換,否則的話,它只替換第一個匹配的字串;

replacement 既可以是字串,也可以是函式,如果它是字串的話,那麼匹配的將與字串替換,replacement中的$有具體的含義,如下:

$1,$2,$3….$99 含義是:與regexp中的第1到第99個子表示式相匹配的文字。

$& 的含義是:與RegExp相匹配的子字串。

lastMatch或RegExp[“$_”]的含義是:返回任何正規表示式搜尋過程中的最後匹配的字元。

lastParen或 RegExp[“$+”]的含義是:返回任何正規表示式查詢過程中最後括號的子匹配。

leftContext或RegExp[“$`”]的含義是:返回被查詢的字串從字串開始的位置到最後匹配之前的位置之間的字元。

rightContext或RegExp[“$'”]的含義是:返回被搜尋的字串中從最後一個匹配位置開始到字串結尾之間的字元。

如下測試程式碼:

4. split()方法: 該方法把一個字串分割成字串陣列。

 基本語法如:stringObject.split(separator,howmany);

@param(引數) 

   1. separator[必填項],字串或正規表示式,該引數指定的地方分割stringObject; 

   2. howmany[可選] 該引數指定返回的陣列的最大長度,如果設定了該引數,返回的子字串不會多於這個引數指定的陣列。如果沒有設定該引數的話,整個字串都會被分割,不考慮他的長度。

  @return(返回值) 一個字串陣列。該陣列通過在separator指定的邊界處將字串stringObject分割成子字串。

測試程式碼如下:

1-2 RegExp物件方法

   1. test()方法:該方法用於檢測一個字串是否匹配某個模式;

   基本語法:RegExpObject.test(str);

   @param(引數) str是需要檢測的字串;

   @return (返回值) 如果字串str中含有與RegExpObject匹配的文字的話,返回true,否則返回false;

如下測試程式碼:

2. exec()方法: 該方法用於檢索字串中的正規表示式的匹配。

 基本語法:RegExpObject.exec(string)

@param(引數):string【必填項】要檢索的字串。

@return(返回值):返回一個陣列,存放匹配的結果,如果未找到匹配,則返回值為null;

注意:該返回的陣列的第一個元素是與正規表示式相匹配的文字,該方法還返回2個屬性,index屬性宣告的是匹配文字的第一個字元的位置;input屬性則存放的是被檢索的字串string;該方法如果不是全域性的話,返回的陣列與match()方法返回的陣列是相同的。

如下測試程式碼:

瞭解正則中的普通字元

字母,數字,漢字,下劃線及一些沒有特殊定義的標點符號,都屬於普通字元,正則中的普通字元,在匹配字串的時候,匹配與之相同的字元即可~ 比如如下程式碼:

var str = “abcde”;

console.log(str.match(/a/)); // [“a”, index: 0, input: “abcde”]

如上程式碼,字串abcde匹配a的時候,匹配成功,索引位置從0開始;

瞭解正則中的方括號[]的含義

方括號包含一系列字元,能夠匹配其中任意一個字元, 如[abc]可以匹配abc中任意一個字元,使用[^abc]包含的字元abc,則能夠匹配abc字元之外的任何一個字元,只能是一個字元。如下的含義:

[abc]:  查詢在方括號中的任意一個字元;

[^abc]: 查詢不在方括號中的任意一個字元;

[0-9]: 查詢0-9中的任意一個數字;

[a-z]: 查詢從小寫a到z中的任意一個字元;

(red|blue|green); 查詢小括號中的任意一項,小括號中的 | 是或者的意思;

列舉1:表示式[bcd][bcd] 匹配 “abcde”時候,匹配成功,內容是bc,匹配到的位置開始於1,結束與3;如下程式碼:

var str = “abcde”;

console.log(str.match(/[bcd][bcd]/)); // [“bc”, index: 1, input: “abcde”]

理解javascript中的元字元

元字元 描述
. 查詢任意的單個字元,除換行符外
\w 任意一個字母或數字或下劃線,A_Za_Z0_9,_中任意一個
\W 查詢非單詞的字元,等價於[^A_Za_z0_9_]
\d 匹配一個數字字元,等價於[0-9]
\D 匹配一個非數字字元,等價於[^0-9]
\s 匹配任何空白字元,包括空格,製表符,換行符等等。等價於[\f\n\r\t\v]
\S 匹配任何非空白字元,等價於[^\f\n\r\t\v]
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置,比如’er\b’可以匹配”never”中的”er”,但是不能匹配”verb”中的”er”
\B 匹配非單詞邊界,’er\B’能匹配’verb’中的’er’,但不能匹配’never’中的’er’
查詢NUL字元。
\n 匹配一個換行符
\f 匹配一個換頁符
\r 匹配一個回車符
\t 匹配一個製表符
\v 匹配一個垂直製表符
\xxx 查詢一個以八進位制數xxx規定的字元
\xdd 查詢以16進位制數dd規定的字元
\uxxxx 查詢以16進位制數的xxxx規定的Unicode字元。

1. 元字元. 用於匹配任何單個字元(除了換行符以外);

基本語法:new RegExp(“regexp.”) 或者直接量語法 /regexp./

比如程式碼如下:

var str = “abcde”;

console.log(str.match(/a.c/)); // [“abc”, index: 0, input: “abcde”]

2. \w; 查詢任意一個字母或數字或下劃線,等價於A_Za_z0_9,_

基本語法:new RegExp(“\w”); 或 直接量語法:/\w/

比如程式碼如下:

var str = “abcde”;

// 匹配單個字元,找到一個直接返回

console.log(str.match(/\w/)); // [“a”, index: 0, input: “abcde”]

// 匹配所有字元

console.log(str.match(/\w+/)); //[“abcde”, index: 0, input: “abcde”]

3. \W; 查詢非單詞的字元,等價於[^A_Za_z0_9_]

基本語法:new RegExp(“\W”) 或直接量 /\W/

var str = “abcde”;

// 匹配單個字元,沒有找到返回null

console.log(str.match(/\W/)); // null

4. \d;匹配與一個數字字元,等價於[0-9];

基本語法:new RegExp(“\d”); 或 直接量語法:/\d/

程式碼如下:

var str = “abcde111”;

console.log(/\d/g.exec(str)); // [“1”, index: 5, input: “abcde111”]

5. \D; 匹配一個非數字字元,等價於[^0-9]

基本語法:new RegExp(“\D”) 或直接量 /\D/

如下測試程式碼:

var str = “abcde111”;

console.log(/\D+/g.exec(str)); // [“abcde”, index: 0, input: “abcde111”]

6. \s;匹配任何空白字元,包括空格,製表符,換行符等等。等價於[\f\n\r\t\v]

基本語法:new RegExp(“\s”) 或直接量 /\s/

如下測試程式碼:

var str=”Is this all there is?”;

console.log(/\s/g.exec(str)); // [” “, index: 2, input: “Is this all there is?”]

7. \S;匹配任何非空白字元,等價於[^\f\n\r\t\v]

基本語法:new RegExp(“\S”) 或直接量 /\S/

如下測試程式碼:

var str=”Is this all there is?”;

console.log(/\S+/g.exec(str)); // [“Is”, index: 0, input: “Is this all there is?”]

8. \b; 匹配一個單詞邊界,也就是指單詞和空格間的位置,比如’er\b’可以匹配”never”中的”er”,但是不能匹配”verb”中的”er”

基本語法:new RegExp(“\bregexp”) 或直接量 /\bregexp/

如下測試程式碼:

var str=”Is this all there is?”;

console.log(/\bthis\b/g.exec(str)); // [“this”, index: 3, input: “Is this all there is?”]

9. \B; 匹配非單詞邊界,’er\B’能匹配’verb’中的’er’,但不能匹配’never’中的’er’

基本語法:new RegExp(“\Bregexp”) 或直接量 /\Bregexp/

測試程式碼如下:

var str=”Is this all there is?”;

console.log(/\Bhi/g.exec(str)); // [“hi”, index: 4, input: “Is this all there is?”]

10. \n; 匹配一個換行符;返回換行符被找到的位置。如果未找到匹配,則返回 -1。

基本語法:new RegExp(“\n”) 或直接量 /\n/

如下測試程式碼:

var str=”Is this all \nthere is?”;

console.log(/\n/g.exec(str)); // [“換行符”, index: 12, input: “Is this all ↵there is?”]

11. \xxx; 查詢一個以八進位制數xxx規定的字元,如果未找到匹配,則返回 null。

基本語法:new RegExp(“\xxx”) 或直接量 /\xxx/

如下測試程式碼:

var str=”Visit W3School. Hello World!”;

console.log(/\127/g.exec(str)); // [“W”, index: 6, input: “Visit W3School. Hello World!”]

如上程式碼分析:127的八進位制轉換為10進位制的值等於 1*8的二次方 + 2*8的一次方 + 7*8的0次方 = 64 + 16 + 7 = 87 而W的ASCLL編碼轉換為10進位制也是87,因此列印W

12. \xdd;查詢以16進位制數dd規定的字元。如果未找到匹配,則返回 null。

基本語法:new RegExp(“\xdd”) 或直接量 /\xdd/

如下測試程式碼:

var str=”Visit W3School. Hello World!”;

console.log(/\x57/g.exec(str)); // [“W”, index: 6, input: “Visit W3School. Hello World!”]

W的16進位制數等於57;

13.\uxxxx; 查詢以16進位制數的xxxx規定的Unicode字元。

基本語法:new RegExp(“\uxxx”) 或直接量 /\uxxx/

如下測試程式碼:

var str=”Visit W3School. Hello World!”;

console.log(/\u0057/g.exec(str)); // [“W”, index: 6, input: “Visit W3School. Hello World!”]

需要轉義的特殊字元前面加 \

匹配輸入字串的結尾位置,如果需要匹配 本身的話,使用\$

^ 匹配輸入字串的開始位置,匹配^本身的話,使用\^

* 匹配前面的子表示式的零次或者多次,匹配*本身的話,使用\*

+ 匹配子表示式的1次或者多次,匹配+本身的話,使用\+

. 匹配除換行符之外的任何一個字元,匹配.本身的話,使用\.

[ 匹配一箇中括號開始,匹配本身的,使用\[

? 匹配前面的子表示式的零次或者1次,或指明一個非貪婪限定符,要匹配本身的話,使用\?

\ 匹配本身的話,請使用\\

{ 標記限定符開始的地方,要匹配{ ,請使用\{

| 指明多項中的一個選擇,可以理解含義為或的意思,匹配本身的話,使用\|

瞭解量詞

量詞 描述
n+ 匹配任何至少包含一個n的字串
n* 匹配零個或者多個n的字串
n? 匹配零個或者1個n的字串
n{x} 匹配包含x個n的序列字串
n{x,y} 匹配至少x個,最多y個n的字串
n{x,} 匹配至少x個的字串
n$ 匹配以n結尾的字串
^n 匹配以n開頭的字串
?=n 匹配其後緊接指定的n字串
?!n 匹配其後沒有緊接指定的n字串

1. n+ 匹配至少包含一個或者多個n的字串。

基本語法:new RegExp(“n+”) 或直接量 /n+/

如下測試程式碼:

2. n* 匹配零個或者多個n的字串。

基本語法:new RegExp(“n*”) 或直接量 /n*/

如下測試程式碼:

3. n?匹配零個或者1個n的字串,可以匹配n字串,也可以只匹配一個n;先儘量匹配,如沒有匹配到,就回溯,再進行不匹配;

基本語法:new RegExp(“n?”) 或直接量 /n?/

如下測試程式碼:

4. n{x}  匹配包含x個的n的序列字串。X必須是數字。

基本語法:new RegExp(“n{x}”) 或直接量 /n{x}/

如下測試程式碼:

5. n{x,y} 匹配包含至少x個的n字串,最多y個n字串

基本語法:new RegExp(“n{x,y}”) 或直接量 /n{x,y}/

如下測試程式碼:

6. n{x,} 匹配至少包含x個n序列的字串;

基本語法:new RegExp(“n{x,}”) 或直接量 /n{x,}/

如下測試程式碼:

7. n$ 匹配任何以n結尾的字串;

基本語法:new RegExp(“n$”) 或直接量 /n$/

如下測試程式碼:

8. ^n 匹配任何以n開頭的字串;

基本語法:new RegExp(“^n”) 或直接量 /^n/

如下測試程式碼:

9. ?=n 匹配任何其後緊接指定字串n的字串;

基本語法:new RegExp(“regexp(?=n)”) 或直接量 /regexp(?=n)/

如下測試程式碼:

10 ?!n 匹配任何其後不緊接n的字串

基本語法:new RegExp(“regexp(?!n)”) 或直接量 /regexp(?!n)/

如下測試程式碼:

11. ^ 以字串開始的地方匹配,不匹配任何字元;

比如:表示式^aaa 在匹配字串 “longen aaa bbb”的時候,匹配的結果是失敗的;因為^的含義是以某某字串開始進行匹配;只有當aaa在字串起始位置才能匹配成功;比如”aaa longen bbb” 才匹配成功;

12. $ 以字串結束的地方匹配,不匹配任何字元;

比如:表示式aaa在匹配字串“longenaaabbb”的時候,匹配的結果是失敗的;因為 的含義是以某某字串結束進行匹配;只有當aaa在字串結束位置才能匹配成功;比如”longen bbb aaa” 才匹配成功;

13. \b 匹配一個單詞邊界,也就是單詞與空格之間的位置,不匹配任何字元;

如下測試程式碼:

14. |  左右兩邊表示式之間 “或” 關係,匹配左邊或者右邊。

如下測試程式碼:

15:()的含義 

在被修飾匹配次數的時候,括號中的表示式可以作為整體被修飾。取匹配結果的時候,括號中的表示式匹配到的內容可以被單獨得到。

貪婪模式與非貪婪模式講解

Javascript中的正則貪婪與非貪婪模式的區別是:被量詞修飾的子表示式的匹配行為;貪婪模式在整個表示式匹配成功的情況下儘可能多的匹配;非貪婪模式在整個表示式匹配成功的前提下,儘可能少的匹配;

一些常見的修飾貪婪模式的量詞如下:

{x,y} ,  {x,} ,  ? ,  * , 和  +

那麼非貪婪模式就是在如上貪婪模式後加上一個?(問號),就可以變成非貪婪模式的量詞;如下:

{x,y}?,{x,}?,??,*?,和 +?

1. 什麼是貪婪模式?

先看如下程式碼:

第一個console.log使用的是貪婪模式,我們來理解下匹配的基本原理;

首先正則是 /<p>.*<\/p>/ 匹配;<p>匹配字串第一個字元匹配失敗,接著往下,直接匹配到<p>時候,匹配成功,接著把匹配的控制權交給.*,從匹配到的<p>位置開始匹配,一直到</p>之前,接著把控制權交給</p>,接著在當前位置下往下匹配,因此匹配到</p>,匹配成功;由於它是貪婪模式,在匹配成功的前提下,仍然會嘗試向右往下匹配,因此會匹配到兩個<p>標籤結束;但是非貪婪模式,也就是第二個console.log();他匹配到第一個p標籤成功後,它就不會再進行匹配,因此列印的值為一個p標籤的內容了;

理解匹配成功前提下的含義: 上面我們解釋了,貪婪模式是要等一個表示式匹配成功後,再往下匹配;比如我們現在接著再看下們的表示式匹配程式碼:

如上程式碼,列印出一個p標籤內容,我們知道.*是貪婪模式匹配,如果按照上面的解釋會列印出2個p標籤的內容,因為這裡在匹配到p標籤後,會繼續匹配後面的yunxi字串,直到整個表示式匹配成功,才提示匹配成功,因此當匹配到第一個yunxi後,第一個子表示式匹配成功,接著嘗試往右繼續匹配,<p></p>都匹配成功,但是yunxi不會匹配boyboy,所以第二次嘗試匹配的子表示式匹配失敗,因此只返回匹配成功後的第一個p標籤的內容了;

我們現在再來看看非貪婪模式的含義:

如下程式碼:

我們先看錶達式1,/<p>.*?<\/p>boyboy/ 匹配str字串,首先先匹配到p標籤內容;但是由於boyboy字串一直沒有匹配到,因此會一直嘗試往後匹配,直到匹配到boyboy字串後,才匹配成功,否則匹配失敗;由於它是非貪婪模式,因此這時候它不會再往下進行匹配,所以匹配就結束了;因此第一個console輸出為<p>我是中國人</p>yunxi<p>我是男人</p>boyboy;

我們可以再來看看貪婪模式 第二個console.log()輸出的; 正規表示式 /<p>.*<\/p>yunxi/ 匹配到第一個p標籤yunxi後,由於它是貪婪的,它還想接著向右繼續匹配,直到匹配完成後,匹配成功,才結束,因此把所有p標籤後面跟隨yunxi的字串都匹配到,且之間的所有的字串都被返回;

 

理解正規表示式匹配原理

我們先來理解下佔有字元和零寬度的含義。

1. 佔有字元和零寬度

     在正規表示式匹配的過程中,如果子表示式匹配到的是字元內容,而非位置的話,並被儲存在匹配的結果當中,那麼就認為該子表示式是佔有字元的;如果子表示式匹配的僅僅是位置,或者說匹配中的內容不儲存到匹配的結果當中,那麼就認為該子表示式是零寬度的。我們先來理解下零寬度的列子,最常見的就是環視~ 它只匹配位置;比如順序環視;環視待會就講;

我們先理解下匹配過程如下圖:

正則匹配方式 /abc/ 

匹配過程:首先由字元a取得控制權,從位置0開始進行匹配,a匹配a,匹配成功;接著往下匹配,把控制權交給b,那麼現在從位置1開始,往下匹配,匹配到字串b,匹配成功,接著繼續往下匹配,位置是從2開始,把控制權交給c,繼續往下匹配,匹配到字串c,匹配成功,所以整個表示式匹配成功;匹配結果為 abc 匹配的開始位置為0,結束位置為3;

含有匹配優先量詞的匹配過程

如下:

源字串abc,正規表示式為ab?c ;量詞?可以理解為匹配優先量詞,在可匹配可不匹配的時候,會優先選擇匹配;當匹配不到的時候,再進行不匹配。先匹配b是否存在,如果不存在的話,就不匹配b;因此結果可以匹配的有 abc,ac等

匹配過程:

首先由字元a取得控制權,從位置0開始匹配,a匹配到字串a,匹配成功;接著繼續匹配,把控制權交給b,b現在就從位置1開始匹配;匹配到字串b,匹配成功;接著就把控制權交給c,c從位置2開始繼續匹配,匹配字串c,匹配成功;整個表示式匹配成功;假如b那會兒匹配不成功的話,它會忽略b,繼續匹配字串c,也就是如果匹配成功的話,結果是ac;

因此abc匹配字串abc,匹配的位置從0開始,到3結束。

如果匹配的結果為ac的話,那麼匹配的位置從0開始,到2結束;

假如我們把字串改為abd,或者abe等其他的,那麼當匹配到最後一個字元的時候,就匹配失敗;

含有忽略優先量詞的匹配過程

量詞?? 含義是 忽略優先量詞,在可匹配和可不匹配的時候,會選擇不匹配,這裡的量詞是修飾b字元的,所以b?? 是一個整體的。匹配過程如下

首先由字元a取得控制權,從位置0開始匹配,有”a”匹配a,匹配成功,控制權交給b?? ;首先先不匹配b,控制權交給c,由c來匹配b,匹配失敗,此時會進行回溯,由b??來進行匹配b,匹配成功,然後會再把控制權交給c,c匹配c,匹配成功,因此整個表示式都匹配成功;

理解正規表示式—-環視

環視只進行子表示式匹配,不佔有字元,匹配到的內容不儲存到最終的匹配的結果,是零寬度的,它匹配的結果就是一個位置;環視的作用相當於對所在的位置加了一個附加條件,只有滿足了這個條件,環視子表示式才能匹配成功。環視有順序和逆序2種,順序和逆序又分為肯定和否定,因此共加起來有四種;但是javascript中只支援順序環視,因此我們這邊來介紹順序環視的匹配過程;

如下說明:

1.  (?=Expression):  

順序肯定環視,含義是所在的位置右側位置能夠匹配到regexp.

2. (?!Expression)

順序否定環視,含義是所在的位置右側位置不能匹配到regexp

順序肯定環視

先看如下圖:

首先我們需要明白的是:^和$ 是匹配的開始和結束位置的;?= 是順序肯定環視,它只匹配位置,不會佔有字元,因此它是零寬度的。這個正則的含義是:

以字母或者數字組成的,並且第一個字元必須為小寫字母開頭;

匹配過程如下:

首先由元字元^取得控制權,需要以字母開頭,接著控制權就交給 順序肯定環視 (?=[a-z]); 它的含義是:要求它所在的位置的右側是有a-z小寫字母開頭的才匹配成功,字元a12,第一個字元是a,因此匹配成功;我們都知道環視都是匹配的是一個位置,不佔有字元的,是零寬度的,因此位置是0,把控制權交給[a-z0-9]+,它才是真正匹配字元的,因此正則[a-z0-9]+從位置0開始匹配字串a12,且必須以小寫字母開頭,第一個字母是a匹配成功,接著繼續從1位置匹配,是數字1,也滿足,繼續,數字2也滿足,因此整個表示式匹配成功;最後一個$符合的含義是以字母或者數字結尾的;

順序否定環視 

當順序肯定環視匹配成功的話,順序否定環視就匹配失敗,當順序肯定環視匹配失敗的話,那麼順序否定環視就匹配成功;

我們先看如下圖:

源字串:aa<p>one</p>bb<div>two</div>cc 

正則:<(?!/?p\b)[^>]+>

正則的含義是:匹配除<p>之外的其餘標籤;

如下圖:

匹配過程如下:

首先由”<” 取得控制權,從位置0開始匹配,第一個位置和第二個位置都是字元a,因此匹配失敗~ 接著從位置2匹配,匹配到<, 匹配成功了,現在控制權就交給(?!/?p\b);?!是順序否定環視,只匹配一個位置,不匹配字元,這個先不用管,首先是 /? 取得控制權,它的含義是:可匹配/,或者不匹配/, 接著往下匹配的是p字元,匹配失敗,進行回溯,不匹配,那麼控制權就到一位了p字元,p匹配p,匹配成功,控制權就交給\b; \b的含義是匹配單詞的邊界符,\b就匹配到了 > ,結果就是匹配成功,子表示式匹配就完成了;/?p\b 就匹配成功了;所以(?!/?p\b) 這個就匹配失敗了;從而使表示式匹配失敗;我們繼續往下匹配,從b字元開始,和上面一樣匹配失敗,當位置是從14開始的時候 < 字元匹配到”<”,匹配成功,把控制權又交給了(?!/?p\b), 還是/?取得控制權,和上面匹配的邏輯一樣,最後?p\b匹配失敗了,但是(?!/?p\b) 就匹配成功了,因此這一次表示式匹配成功;如下程式碼匹配:

var str = “aa<p>one</p>bb<div>two</div>cc”;

// 匹配的結果為div,位置從14開始 19結束

console.log(str.match(/<(?!\/?p\b)[^>]+>/)[0]);

理解正規表示式—捕獲組

捕獲組就是把正規表示式中子表示式匹配的內容,儲存到記憶體中以數字編號或顯示命名的組裡,方便後面使用;可以在正規表示式內部使用,也可以在外部使用;

捕獲組有2種,一種是捕獲性分組,另一種是 非捕獲性分組;

我們先來看看捕獲性的分組語法如下:

捕獲組分組語法:(Expression)

我們都知道中括號是表示範圍內選擇,大括號表示重複次數,小括號的含義是允許重複多個字元;

捕獲性分組的編號規則:編號是按照”(”出現的順序,從左到右,從1開始進行編號;

比如如下程式碼:

反向引用

反向引用標識由正規表示式中的匹配組捕獲的子字串。每個反向引用都由一個編號或名稱來標識;並通過 “\編號” 表示法來進行引用;

理解非捕獲性分組

並不是所有分組都能建立反向引用,有一種分組叫做非捕獲性分組,它不能建立反向引用,要建立一個非捕獲性分組,只要在分組的左括號的後面緊跟一個問號與冒號就ok;非捕獲分組的含義我們可以理解為如下:子表示式可以作為被整體修飾但是子表示式匹配的結果不會被儲存;如下:

如上:我們來分析下:正則/<(?:.|\s)*?>/g 的含義是:g是修飾符,全域性匹配的含義;使用非捕獲性分組?: 的含義是 子表示式可以作為被整體修飾但是子表示式匹配的結果不會被儲存;因此:正則/<(?:.|\s)*?>/g 的含義變為:匹配以< 開頭 及 > 結束的所有字元;(?:.|\s)*? 含義是:. 代表任意字元,| 含義是或者的意思,\s 是匹配空格的意思;*號修飾符的含義是零個或者多個的意思;後面的?(問號)代表可匹配,可不匹配的含義;優先是可匹配;總起來的意思是:全域性匹配字串html 中的 以<開頭 以>結尾的所有字元 替換成 空字串,因此留下來就是文字;當然我們使用捕獲性分組也可以得到同樣的結果~

反向引用詳細講解

捕獲性分組取到的內容,不僅可以在正規表示式外部通過程式進行引用,也可以在正規表示式內部進行引用,這種引用方式就叫做反向引用。

反向引用的作用是:是用來查詢或限定重複,查詢或限定指定標識配對出現等。

捕獲性分組的反向引用的寫法如:\number

Number是十進位制數字,即捕獲組的編號。

反向引用的匹配原理

捕獲分組在匹配成功時,會將子表示式匹配到的內容,儲存到記憶體中一個以數字編號的組裡,可以簡單的認為是對一個區域性變數進行了賦值,這時就可以通過反向引用,引用這個區域性變數的值。一個捕獲分組在匹配成功之前,它的內容可以是不確定的,一旦匹配成功了,它的內容就確定了,反向引用的內容也就確定了。

比如如下程式碼:

程式碼分析:對於如上程式碼中的正則 /([ab])\1/, 捕獲組中子表示式[ab];可以匹配a,也可以匹配b,但是如果匹配成功的話,那麼它的反向引用也就確定了,如果捕獲分組匹配到的是a,那麼它的反向引用就只能匹配a,如果捕獲分組匹配到的是b,那麼它的反向引用就只能匹配到b;\1的含義是 捕獲分組匹配到是什麼,那麼它必須與捕獲分組到是相同的字元;也就是說 只能匹配到aa或者bb才能匹配成功;

該正則匹配的過程我們可以來分析下:

字串匹配正則/([ab])\1/, 在位置0處開始匹配,0處字元是l,很明顯不滿足,把控制權就交給下一個字元,一直到第6個字元,才匹配到a,匹配成功,把控制權交給\1, 也就是反向引用和分組中是相同的字元,因此也匹配a,字串中下一個字元也是a,因此匹配成功,因此整個表示式找到匹配的字元,匹配的位置開始於6,結束與8;我們再可以匹配b,原理和上面一樣,這裡就不再多解釋了;

正規表示式實戰

1. 匹配以數字結尾的;

正則:/\d+$/g;

2. 去掉空格;

var str = “我 是 龍 恩”;

console.log(str.replace(/\s+/g,””));//我是龍恩

3. 判斷字串是不是由數字組成;

var str = “123344我 是 龍 恩 1123344”;

console.log(/^\d*$/.test(str)); //false

var str2 = “123445566”;

console.log(/^\d*$/.test(str2)); // true

4. 電話號碼正則

分析如下:電話號碼有區號(3-4位數字),區號之後使用 ”-” 與電話號碼連線;

區號正則:^\d{3,4}

電話號碼7~8位 正則 \d{7,8}

電話號碼也有分機號,分機號為3-4位數字,非必填項,如果要填寫的話,則以”-”與電話號碼相連線。

正則(-\d{3,4})?

因此正則匹配電話號碼正則為:

/^\d{3,4}-/d{7,8}(-\d{3,4})?$/;

5. 手機號碼正則

手機號碼需要匹配;手機號碼開頭不以0開始的,並且是11位數字,目前的手機號碼有如下開頭的:13,14,15,17,18開頭的;因此正則如下:

/(^1[3|4|5|7|8][0-9]{9}$)/

如下測試程式碼:

var str = 15606512345;

var reg = /(^1[3|4|5|7|8][0-9]{9}$)/;

console.log(reg.test(str)); //true

6. 刪除字串左右空格

7. 限制文字框只能輸入數字和小數點(二位小數點)

分析:開頭有0個或者多個數字,中間有0個或者1個小數點,小數點後面有0個或者最多2個數字;

正則:

8.替換小數點前面的內容為指定內容

程式碼分析如下:

如上程式碼的含義是 使用正則replace替換操作

找出以字母數字下劃線開頭的字元,前面以\b分隔單詞與邊界的地方

因此會找出第一個字串中第一個開頭的字元,後面是以捕獲性分組來匹配

後面緊跟著一個.號的匹配,分組只匹配位置,不匹配字元,是零寬度的;

9. 匹配中文的正則

使用 Unicode,必須使用\u開頭,接著是字元編碼的四位16進製表現形式。

console.log(/[\u4E00-\u9FA5\uf900-\ufa2d]/g.test(“我是”)); //true

10. 返回字串中 中文字元的個數。

分析:使用replace方法把不是中文字元全部替換成空

返回被替換的字元,因此是中文字元;

程式碼如下:

11. 正則獲取ip地址的前三段

比如如:192.168.16.162 需要變成 192.168.16

 分析:使用正則匹配 .號後面帶1-3位數字即可,

 且以數字結尾的,把他們替換成空字串。

程式碼如下:

12. 匹配標籤中的內容

比如匹配如程式碼 <ul><li>aaa</li><li>bbb</li></ul>

分析: 想獲取ul中的內容,可以對匹配的內容使用分組

然後列印RegExp.$1 就獲取到分組的內容了; 匹配所有字元

使用[\s\S]+ 空白和非空白的所有字元,且使用修飾符g代表全域性的

如下程式碼:


13. 匹配標籤中的文字。

匹配文字思路:可以先把字串內的所有標籤替換成空字串

因此返回的就是文字了;

正則/<\/?[\s\S]+?>/gi

如下程式碼:

14. 正則獲取檔名

檔名有如下幾種:

1. c:\images\tupian06.jpg

2. C:06.JPG

3. “c:\\images\\tupian\06.jpg”;

4. “c:\\images\\tupian\\aa.jpg”;

5. “c:/images/tupian/test2.jpg”;

正則如:/[^\\\/]*[\\\/]+/gi;

上面的正則含義是:[^\\\/]* 不以一個\ 或者 2個\\ 或者 /(需要轉義,使用\)這樣的反斜槓開頭的

零個或者多個字元,後面緊跟以一個\ 或者 兩個\\ 或者 /(需要轉義,使用\)這樣一個或者多個分隔符

全域性匹配;

程式碼如下:

15. 絕對路徑變成相對路徑

比如絕對路徑 http://172.16.28.162/images/a.jpg 需要替換成

./images/a.jpg

使用正則匹配 http:// //需要使用轉義字元轉義的 繼續匹配除/以外的任何一個字元

直到有反斜槓/為止;然後替換成 . 字元

程式碼如下:

16. 使用者名稱正則

匹配規則:只能是中文,英文,數字,下劃線,4-16個字元;

匹配中文字元正則:/[\u4E00-\u9FA5\uf900-\ufa2d]/

\w是 匹配英文,數字,下劃線

測試程式碼如下:

17. 匹配英文地址

匹配規則:包含點,字母,空格,逗號,數字,但是開頭和結尾必須為字母

分析:開頭必須為字母可以這樣寫 /^[a-zA-Z]/

結尾必須為字母可以這樣寫:/[a-zA-Z]+$/

中間包含點,字母,空格,逗號,數字的正則:/[\.a-zA-Z\s,0-9]*?/

外面的*號是0個或者多個,後面的問號? 代表可有可無;有就匹配,沒有就不匹配;

測試程式碼如下:

18 匹配價格

匹配規則: 開頭有0個或者多個數字,中間可能有一個小數點,後面有可能有0-2位小數

正則:/^\d*(\.\d{0,2})?$/

程式碼如下測試

19. 身份證號碼的匹配

匹配規則:身份證號碼有15位或者18位,其中最後一位可能是X,其他全是數字

正則: /^(\d{14}|\d{17})(\d|[xX])$/

20. 單詞的首字母大寫

匹配字串,讓其字串的首個字母大寫

正則:/\b(\w)|\s(\w)/g

測試程式碼如下:

21. 驗證日期格式

日期格式有2種 第一種是yyyy-mm-dd 或 yyyy/mm/dd

分析 月和天數可以有1位或者2位

正則:/^\d{4}[-\/]\d{1,2}[-\/]\d{1,2}$/;

測試程式碼如下:

22. 驗證郵箱的正規表示式

思路分析: 郵箱的規則是: 由3部分組成

由1個或者多個字母數字下劃線和槓 + @ + 1個或者多個字母數字下劃線和槓 + . + 1個或者多個字母數字下劃線和槓

因此正則:/^([a-zA-Z_0-9-])+@([a-zA-Z_0-9-])+(\.[a-zA-Z_0-9-])+$/

測試程式碼如下:

23. 匹配程式碼中的a連結

比如<a href=’http://www.baidu.com’>222</a> 匹配這樣的

使用正則:/<a[.\s]*href\s*=\s*’http:\/\/.*’>\w*<\/a>/gi;

測試程式碼如下:

24. 正則判斷標籤是否閉合

沒有閉合的標籤有2種 型別 一種像img標籤那樣的

<img src=””

還有一種像div或者p標籤那樣的

<div>aaa</div>

<p></p>

分析:先匹配起始標籤 如<img 或 <p 使用正則:/<[a-z]+/i

接著匹配標籤裡面的多個屬性 使用正則 /(\s*\w*?\s*=\s*.+?)*(\s*?>[\s\S]*?(<\/\1>)+|\s*\/>)/i

因此整個正規表示式合併為 /<([a-z]+)(\s*\w*?\s*=\s*.+?)*(\s*?>[\s\S]*?(<\/\1>)+|\s*\/>)/i

正則分析如下:

首先我們匹配像img標籤或者div標籤的開頭位置時候 <img 或 <div 使用正則 /<([a-z]+)/i 以 < 開始 [a-z]中任意一個字元,修飾符+是一個或者多個字元 i代表不區分大小寫

(\s*\w*?\s*=\s*.+?)*的含義是:比如<img src = “” 或 <div id = “” 先\s*匹配0個或多個空白 \w* 匹配0個或者多個(數字或者字母或下劃線) 後面的問號?(儘可能少的匹配)

接著\s* 匹配0個或者多個空白 = 號緊接後面的 \s* 也是匹配0個或者多個空白 .+? 的含義是匹配除換行符之外的任意一個或多個字元(儘可能少的匹配);

下面我們繼續看標籤的閉合 標籤閉合有2種,一種像img這樣的 <img src=””/> 還有一種是 <div></div>這樣的;

如果是類似img標籤這樣的話,匹配結束字元為 /> 匹配正則為:(\s*\/>); 如果是div這樣的話 正則為:(\s*?>[\s\S]*?<\/\1>)

<\/\1> 的含義是:指的是 ([a-z]+) 這個分組

整個正則 /<([a-z]+)(\s*\w*?\s*=\s*”.+?”)*(\s*?>[\s\S]*?<\/\1>)|\s*\/>/i

 注意:在元字元* 或者 + 號後加一個問號(?) 目的是 儘可能少的匹配;


25. 獲取標籤裡面的內容

正則和上面一樣 只是使用了一個分組後,再獲取那個分組即可;

26. 正則判斷是否為數字和字母的混合

規則:字母和數字的混合

正則如: /^(([a-z]+)([0-9]+)|([0-9]+([a-z]+)))[a-z0-9]*$/i

分析:^([a-z]+)([0-9]+) 含義是 以1個或多個字母開頭 後面緊跟1個或者多個數字

^([0-9]+([a-z]+)) 或者是以1個或者多個數字開頭 後面緊跟1個或者多個字母

[a-z0-9]*$ 後面還可以緊跟數字或者字母0個或者多個

測試程式碼如下:

27. 將阿拉伯數字轉換為中文大寫字元

28. 替換文字中的url為連結

比如一段文字中有 aaaaahttp://www.baidu.combbbbb 需要替換成 aaaaa<a href=”http://www.baidu.com”>http://www.baidu.com</a>bbbbb

分析:最主要的還是需要正則匹配http://www.baidu.com 的url

正則如:/http:\/\/\w*(\.\w*)+/ig;

測試程式碼如下:

相關文章