JS正規表示式總結

BothEyes1993發表於2018-12-20

第一部分 基礎知識

一、正則申明方式

1、建構函式方式

var reg = new RegExp('\d', 'gi');
複製程式碼

● 通過 new 構造一個正規表示式物件,其中第一個引數 ‘\d’ 是正則內容,第二個引數 ‘gi’ 是修飾符。兩個引數皆為字串型別

● 修飾符的作用是對匹配過程進行限定

● 修飾符有三種:i, g, m,可以同時出現,沒有順序(即 gi 與 ig 一樣),請參考下方說明

修飾符 說明
i 忽略大小寫匹配
g 全域性匹配,即是匹配一個後繼續匹配,直到結束
m 多行匹配,即是遇到換行後不停止匹配,直到結束

說明:● [a-z] 表示從小寫字母a到小寫字母z之間的任意字元(含a和z),下文會有詳細說明● + 表示至少出現一次● \n 在js中表示換行● [1] 表示以任意小寫字母開頭的行

'aBcd efg'.match(/[a-z]+/);
// ["a"]'aBcd efg'.match(/[a-z]+/i);
// ["aBcd"]'aBcd efg'.match(/[a-z]+/g);
// ["a", "cd", "efg"]'aBcd efg'.match(/[a-z]+/gi);
// ["aBcd", "efg"]'aB\ncd\n efg'.match(/^[a-z]+/m);
// ["a"]'aB\ncd\n efg'.match(/^[a-z]+/g);
// ["a"]'aB\ncd\n efg'.match(/^[a-z]+/gm);
// ["a", "cd"]// 注意不是 ["a", "cd", "efg"]複製程式碼

2、字面量方式

相比較上一種方式,這一種更為常見,上面示例也都使用了這種方式

var reg = /\d/gi;
複製程式碼

兩個斜線內為正則的內容,後面可以跟修飾符,與第一種建構函式方式相比更簡潔,缺點是正則內容不能拼接,對於大多數場景倆說足夠了

二、正則相關符號

1、方括號 [] 用法

用於查詢方括號內的任意字元:

在這裡插入圖片描述

注意:1)^ 在 [] 內開始位置及正則雙斜線開始位置有特殊含義,其他位置表示 ^ 字元本身

● // 正則開頭位置表示以某某開頭的字串,如下表示以大寫或小寫字母開頭的且連續為字母的字串:

'adobe 2016'.match(/^[a-zA-Z]+/);
// ["adobe"]複製程式碼

● 在正則 或 匹配中(即 | 匹配),表示 或者以某某字元開始的字串,如下表示匹配 連續數字 或 以小寫字母開頭且連續為小寫字母的字串,所以返回結果包含2016 和 adobe,注意返回結果不是 [“2016”, “adobe”]

'adobe2016ps'.match(/\d+|^[a-z]+/g);
// ["adobe", "2016"]複製程式碼

● 在 [] 內開始位置時,表示不匹配 [] 內除 ^ 以外的所有字元:

'adobe'.match(/[^abc]/g);
// ["d", "o", "e"]複製程式碼

注: $ 與 ^ 的前兩個用法相似,只不過匹配的是以某某字元結尾的字串,舉例:

'adobe 2016'.match(/\d+|[a-z]+$/g);
// ["2016"]'adobe'.match(/\d+|[a-z]+$/g);
// ["adobe"]複製程式碼

2)- (連字元)表示左邊字元的 ASCII 值到右邊字元 ASCII 編碼值之間及左右字元自身的所有字元

'adobe PS 2016'.match(/[a-g]/g);
// ["a", "d", "b", "e"]複製程式碼

3)- 連字元左側的字元對應的 ASCII 值一定要小於或等於右側的字元,否則會報語法錯誤

'adobe'.match(/[z-a]/);
// Uncaught SyntaxError: Invalid regular expression: /[z-a]/: Range out of order in character class...複製程式碼

4)如果希望對連字元 – 本身進行匹配,需要用反斜線轉義

'adobe-2016'.match(/[a-g\-]/g);
// ["a", "d", "b", "e", "-"]複製程式碼

5)檢視 ASCII 表就會發現,大寫字母的 ASCII 值是小於小寫字母的,因此下面用法會報語法錯誤

'adobe-2016'.match(/[a-Z]/g);
// Uncaught SyntaxError: Invalid regular expression: /[a-Z]/: Range out of order in character ...複製程式碼

那麼問題來了,如果要表示所有字母,不區分大小寫怎麼辦呢?其實有兩種方式:A、第一種是使用修飾符 i,前面提到過。舉例:

'adobe-PS'.match(/[a-z]/gi);
// ["a", "d", "o", "b", "e", "P", "S"]複製程式碼

B、第二種是在正則中明確指明大小寫字母,舉例:

'adobe-PS'.match(/[a-zA-Z]/g);
// ["a", "d", "o", "b", "e", "P", "S"]複製程式碼

返回結果跟第一種一樣。當然這個例子有些特殊:匹配了所有大小寫字母。當只匹配部分大小寫字母的時候只能使用第二種方式,在此就不做示例了,讀者可以自己測試

6)匹配大小字母不能寫成 [A-z],雖然不會報語法錯誤,但隱式的放大了匹配範圍,檢視 ASCII 會發現,在大寫字母 Z 到小寫字母 a 之間還有 [、 \、 ]、 ^、 _、 ` 這6個字元,因此不能這麼寫。

7)想必有同學會問, \w 不也可以匹配字母麼?是的,\w 確實可以匹配字母,但跟上面說的一樣,也隱式的放大了匹配範圍,\w 除了匹配大小字母外還匹配了數字和下劃線,即 \w 與 [A-Za-z0-9_] 等價,當然 A-Z、a-z、0-9(等價於\d)、_這四組沒順序之分

2、特殊含義字元

● . 匹配任意單個字元,除換行和結束符

'1+0.2*2=1.4'.match(/.{2
}/g);
// ["1+", "0.", "2*", "2=", "1."]複製程式碼

● \w 匹配任意單詞字元(數字、字母、下劃線),等價於[A-Za-z0-9_]

'ad34~!@$ps'.match(/\w/g);
// ["a", "d", "3", "4", "p", "s"]複製程式碼

● \W 匹配任意單詞字元,與\w相反,等價於[^A-Za-z0-9_]

'ad34~!@$ps'.match(/\W/g);
// ["~", "!", "@", "$"]複製程式碼

● \d 匹配數字,等價於 [0-9]

'ps6'.match(/\d/g);
// ["6"]複製程式碼

● \D 匹配非數字,等價於 [0-9]

'ps6'.match(/\D/g);
// ["p", "s"]複製程式碼

● \s 匹配空白字元,主要有(\n、\f、\r、\t、\v),注意’a\sb’中的\s依然是字元s,所以’a\sb’.match(/\s/g)返回 null

'adobe ps'.match(/\s/g);
// [" "]複製程式碼

● \S 匹配非空白字元,與\s相反

'adobe ps'.match(/\S/g);
// ["a", "d", "o", "b", "e", "p", "s"]複製程式碼

● \b 匹配單詞邊界,注意連續的數字、字母或下劃線組成的字串會認為一個單詞

'adobe(2016) ps6.4'.match(/\b(\w+)/g);
// ["adobe", "2016", "ps6", "4"]複製程式碼

● \B 匹配非單詞邊界,仔細體會下面的示例與\b的結果

'adobe(2016) ps6.4'.match(/\B(\w+)/g);
// ["dobe", "016", "s6"]複製程式碼

● \0 匹配NUL字元

'\0'.match(/\0/);
// ["NUL"]複製程式碼

● \n 匹配換行符(編碼:10,newline)

'adobe\nps'.match(/\n/).index;
// 5複製程式碼

● \f 匹配換頁符

'adobe\fps'.match(/\f/).index;
// 5複製程式碼

● \r 匹配回車符(編碼:13,return)

'adobe\rps'.match(/\r/).index;
// 5複製程式碼

● \t 匹配製表符,鍵盤tab對應的字元

'adobe\tps'.match(/\t/).index;
// 5複製程式碼

● \v 匹配垂直製表符

'adobe\vps'.match(/\v/).index;
// 5複製程式碼

● \xxx 匹配以八進位制數xxx規定的字元

'a'.charCodeAt(0).toString(8);
// "141"'adobe ps'.match(/\141/g);
// ["a"]複製程式碼

● \xdd 匹配以十六進位制數dd規定的字元

'a'.charCodeAt(0).toString(16);
// "61"'adobe ps'.match(/\x61/g);
// ["a"]複製程式碼

● \uxxxx 匹配以十六進位制數xxxx規定的 Unicode字元,注意位數不夠需要補0

'a'.charCodeAt(0).toString(16);
// "61"'adobe ps'.match(/\u0061/g);
// ["a"]複製程式碼

注意:window系統回車換行符為\r\n,linux系統下沒有\r,linux系統通過vi編輯器開啟window系統的文字檔案時候,經常在行尾出現^M符號,也就是\r的原因,解析文字的時候需要注意相關判斷。

3、量詞說明

● n+ 匹配包含至少一個n的字串

'adobe paas'.match(/a+\w+/g);
// ["adobe", "aas"]複製程式碼

● n* 匹配包含零個或多個n的字串

'ab3 aa12bb'.match(/a*\d+/g);
// ["3", "aa12"]複製程式碼

● n? 匹配包含零個或一個n的字串

'ab3 aa12bb'.match(/a?\d+/g);
// ["3", "a12"]複製程式碼

● n{x
} 匹配包含連續x個n的字串

'ab3 aa12bb aaa34'.match(/a{2
}\d+/g);
// ["aa12", "aa34"]複製程式碼

● n{x,y
} 匹配包含至少連續x個且最多連續y個n的字串

'a3 aaa12bb aaaaaaa34'.match(/a{2,4
}\d+/g);
// ["aaa12", "aaaa34"]複製程式碼

● n{x,
} 匹配包含至少連續x個n的字串

'a3 aaa12bbaa4'.match(/a{2,
}\d+/g);
// ["aaa12", "aa4"]複製程式碼

由上可知,以下 表示式1 與 表示式2 等價

表示式1 表示式2
n+ n{1,
}
n* n{0,
}
n? n{0,1
}

4、符號說明

符號 {
}、^、$、*、+、?、[]、[^]、- 已經在前面介紹過,接下來看下其他特殊字元● a|b 匹配包含a或b的字串

'adobe ps13'.match(/([a-g]+l\d+)/g);
// ["ad", "be", "13"]複製程式碼

● / 字面量方式申明正則時的界定符

'adobe'.match(/\w+/);
// ["adobe"]複製程式碼

● \ 普通反斜線字元

'a\\dobe'.match(/\\/);
// ["\"]複製程式碼

5、小括號 () 用法

正則在非全域性(g)模式下,通過match方式,返回的陣列第一個值整體匹配的字串,其他值為通過括號分組匹配到的1)捕獲用法● 表示對匹配的字串進行分組

'adobe cs9cs10, adobe cs11'.match(/([a-z]+\d+)+/);
// ["cs9cs10", "cs10"]// 注意{2,
}是對 括弧內的匹配 的描述複製程式碼

● 與|一起使用表示選擇性

"he is 12. she is 13. it's box".match(/(it|she|he)\s+is/g);
// ["he is", "she is"]複製程式碼

● 表示對匹配的字串捕獲

'adobe cs9'.match(/[a-z]+\d+/);
// ["cs9"]'adobe cs9'.match(/[a-z]+(\d+)/);
// ["cs9", "9"]複製程式碼

● 表示對匹配的字串反向引用,引用從 \1 開始,從正則左側第一個左括號(當然要是閉合的括號才行)開始計算,每多一對括號,引用數加一,在非捕獲情況下不會加一。但正則比較複雜時,減少引用可以提升匹配效能,關於 非捕獲 下方會詳細介紹引用的結果可以通過 建構函式 RegExp 獲取,即 RegExp.$1一直到 RegExp.$9

'Can you can a can as a canner can can a can?'.match(/([cC]an+)\s+\1/g);
// ["can can"]// 注意 `\1` 等價於正則裡的 `([a-z]+)`,即與下面示例相同'Can you can a can as a canner can can a can?'.match(/[cC]an+\s+[cC]an+/g);
// ["can can"]// 如果把括弧去掉可以看下結果'Can you can a can as a canner can can a can?'.match(/[cC]an+\s+\1/g);
// null複製程式碼

2)非捕獲用法,以(?)形式出現● (?:n ) 表示非捕獲組

// 不使用括號時'adobe12ps15test'.match(/[a-z]+\d+[a-z]+/);
// ["adobe12ps"]複製程式碼

// 使用括號分組

'adobe12ps15test'.match(/[a-z]+(\d+)([a-z]+)/);
// ["adobe12ps", "12", "ps"]'adobe12ps15test'.match(/[a-z]+(?:\d+)([a-z]+)/);
// ["adobe12ps", "ps"]複製程式碼

// 看起來上面語句不用(?:)也可以得到相同結果,即:

'adobe12ps15test'.match(/[a-z]+\d+([a-z]+)/);
// ["adobe12ps", "ps"]複製程式碼

// 注意,但需求希望匹配字母之間的規則複雜時,如希望匹配字母,且字母之間可以為1或3時,但不需要1和3

'adobe11ps15test'.match(/[a-z]+(1|3)+([a-z]+)/);
// ["adobe11ps", "1", "ps"]複製程式碼

// 返回中不希望包含數字怎麼辦,可以使用非捕獲

'adobe11ps15test'.match(/[a-z]+(?:1|3)+([a-z]+)/);
// ["adobe11ps", "ps"]複製程式碼

● (?=n ) 匹配任何其後緊跟字元n的字串,但返回中不包含n

'adobe12ps15test'.match(/[a-z]+(?=\d)/g);
// ["adobe", "ps"]複製程式碼

● (?!n ) 匹配任何其後沒有緊跟字元n的字串,返回中不包含n

'adobe12ps15test'.match(/[a-z]+(?!\d)/g);
// ["adob", "p", "test"]複製程式碼

● (?<
=n ) 匹配任何其前緊跟字元n的字串,返回中不包含n

'adobe12ps15test'.match(/(?<
=\d)[a-z]+/g);
// ["ps", "test"]複製程式碼

● (?<
!n ) 匹配任何其前緊跟字元n的字串,返回中不包含n

'adobe12ps15test'.match(/(?<
!\d)[a-z]+/g);
// ["adobe", "s", "est"]複製程式碼

3)注意● A、如果希望對上面特殊字元本身進行匹配,需要在其前面新增\進行轉移

'11+2=13'.match(/\d+\+/g);
// ["11+"]'(11+2)*2=26'.match(/\(\d+\+\d+\)/g);
// ["(11+2)"]複製程式碼

● B、\舉例

// 注意下面兩個表示式返回的結果'path C:\Windows\System32'.match(/([a-zA-Z]:\\\w+)/g);
// null'path C:\\Windows\\System32'.match(/([a-zA-Z]:\\\w+)/g);
// ["C:\Windows"]複製程式碼

說明: 在申明字串 ‘path C:\Windows\System32’ 時,其中的 ” 就已經被當做轉移符,既是 ‘\W’ ===’W’,所以如果希望申明的字串中包含反斜線,需要在加一個反斜線轉義,即 \

6、正則相關方法

1) RegExp物件相關方法

在這裡插入圖片描述

2)String物件相關方法

在這裡插入圖片描述

3)replace 具體用法顧名思義,是字串替換方法,但用法比較廣泛,相信讀者已經非常熟悉了。在此就當複習了A、 基本用法直接傳入字串進行替換,找到子串後只替換一次,舉例:

'adobe abc'.replace('b', '_')// "ado_e abc"// 注意 第二個 b 沒有被替換複製程式碼

如果希望全部替換,可以使用正規表示式並用全域性修飾符 g 方式,舉例:

'adobe abc'.replace(/b/g, '_')// "ado_e a_c"複製程式碼

B、 高階用法第二個引數可以使用 function,其中有三個引數,分別為 匹配的字串、當前匹配的字串index值、匹配的源字串,最終結果根據每次匹配結果進行相應的替換舉例:

'adobe aacc bbaa'.replace(/a+/g, function(str, index, source){ 
if(index >
0){
return str.toUpperCase();

} else {
return str;

}
});
// "adobe AAcc bbAA"複製程式碼

第二部分 案例分析

一、常見匹配

在寫正則之前,需要注意以下幾點:

  1. 一定要清楚期望的規則是什麼,不然無從匹配
  2. 有些正則不只一種寫法,要注意簡短幹練,複雜的正規表示式不僅難懂,而且容易出BUG,效能也不是很好
  3. 正則雖好,可要適度奧。有些字串處理不一定適合用正則

1、手機號

規則:以1開頭第二位為3、5、7、8且長度為11位的數字組合

/^1[3578]\d{9
}$/.test(13600001111);
// true複製程式碼

2、 字串提取

舉例:提取字串中的數字分析:根據對數字的理解,可能為負數,即-?,如果是負數,其後需要是數字且至少一位,即 -?\d+,小數部分可能有也可能沒有,所以需要對小數部分括弧起來用 ? 或 {0, 1
}限定,因為.是特殊字元需要轉義,於是表示式為:-?\d+(.\d+)?

'(12.3 - 32.3)*2 = -40'.match(/-?\d+(\.\d+)?/g);
// ["12.3", "32.3", "2", "-40"]複製程式碼

二、jQuery中的正則片段

1、表示式在jQuery 3.1.2-pre中找到一個解析單標籤的正則,如下:

/^<
([a-z][^\/\0>
:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>
(?:<
\/\1>
|)$/i複製程式碼

2、分解乍一看有點懵,其實拆解之後就容易理解了,注意拆解的步驟,通常來說:1) 第一步可以先看括號 () ,可以將各個小括號及非括號的分成不同部分,如

/^<
([a-z][^\/\0>
:\x20\t\r\n\f]*) [\x20\t\r\n\f]*\/?>
(?:<
\/\1>
|) $/i複製程式碼

2) 第二步可以將中括號分開

/^<
( [a-z] [^\/\0>
:\x20\t\r\n\f]* ) [\x20\t\r\n\f]* \/?>
(?:<
\/\1>
|) $/i複製程式碼

現在是不是已經很清楚了,接下來分解下,就很容易理解了3、詳解● 1)^<
很明顯在匹配標籤左尖括號括號,且以其開始

● 2)( [a-z] [^\/\0>
:\x20\t\r\n\f]* )
這個括號有兩部分,第一個 [a-z] 沒什麼好解釋,即標籤<
緊跟的必須為字母,因為全域性加了 i(忽略大小寫) 修飾符,所以大小寫字母都可以;[^\/\0>
:\x20\t\r\n\f]*
,及限制標籤名必須以字母開始,且第二個字母不能為/ \0 >
: \20 t \r \n \f
的任意多個字元(思考為什麼),() 表示對標籤的分組,方便取到標籤名

● 3)[\x20\t\r\n\f]* 表示可能含有 [\x20\t\r\n\f] 這些特殊字元,與前面的 [^\/\0>
:\x20\t\r\n\f]*
相似卻不一樣,通過這裡可以看出<
br之後進行回車也能匹配到● 4)/?>
能匹配

● 5)(?:<
\/\1>
|)
這裡不捕獲,並用\1去反向引用第一個括號的表示式 ([a-z][^\/\0>
:\x20\t\r\n\f]*)。
這裡的|表示 <
/\1>
可有可無,即:(?:<
\/\1>
|) 與 (?:<
\/\1>
)?
匹配結果一樣


  1. a-z ↩︎

來源:https://juejin.im/post/5c1bbac9f265da61616ea93d

相關文章