本文內容主要出處爲《JavaScript權威指南》(第六版),筆者只是在搬磚的同時整理思路,有誤望及時指出,感謝!javascript
定義正則表達式
對於正則表達式的概念咱們就很少費口舌了...
在JavaScript中使用正則表達式進行模式匹配離不開RegExp
對象,建立正則對象有兩種方式
1.正則表達式直接量(包含在一對/
之間的字符)html
var reg = /java/;
reg.test('java'); // true複製代碼
2.new RegExp()
java
var reg = new RegExp('java');
reg.test('java'); // true複製代碼
JavaScript也賦予了String
對象進行模式匹配的方法,可是使用這些方法的時候一樣離不開RegExp
例如:c++
var str = 'java';
str.match(/java/); // /java/爲正則直接量複製代碼
String
與 RegExp
如何進行正則匹配,有哪些方法,會在下面兩節講解,這一節(定義正則表達式),主要講述如何定義正則表達式(本節會用到RegExp
的 test
和 exec
方法,如若不瞭解,能夠與最後一節結合來理解)正則表達式
直接字符量表示字符在正則表達式中的表達形式。特殊字符需\
轉義數組
字母、數字 -> 自身
\o -> NUL字符(\u0000)
\t -> 製表符(\u0009)
\n -> 換行符(\u000A)
\v -> 垂直製表符(\u000B)
\f -> 換頁符(\u000C)
\r -> 回車符(\u000D)
...複製代碼
將字符量放入 []
中就成了字符類,字符類匹配它包含的任意一個字符函數
[abc] // 表示a 或者b 或者c
[^abc] // ^在這裏表示取反,除了a、b、c以外的全部字符
[a-z] //-表示鏈接,從a到z的任意字符複製代碼
由上面咱們能夠知道,[0-9]
表示任意數字,像這種經常使用的字符類,JavaScript給他們制訂了本身的特殊轉義字符。ui
. // 除換行符與其餘Unicode行終止符之外的任意字符
\w // 等價於[a-zA-Z0-9_],大小寫字母、數字、下劃線63字符中任意一個
\W // 等價於[^a-zA-Z0-9_]
\s // 任何Unicode空白符
\S // 任何Unicode非空白符
\d // 等價於[0-9]
\D // 等價於[^0-9]
[\b] // \b放入[]中標識退格直接量複製代碼
描述相同字符,屢次出現spa
{n, m} // 最少重複n次,最多重複m次
{n, } // 至少重複n次
{n} //重複n次
? // 等價於 {0, 1}
+ // 等價於 {1,}
* // 等價於 {0,}複製代碼
例如:3d
var reg = new RegExp('a{2,}');
var str = 'aaa';
var str2 = 'a';
reg.test(str); // true
reg.test(str2); // false複製代碼
在這裏會多出一個概念:非貪婪重複
在上述例子中,reg.test(str) === true
咱們用reg.exec(str)
獲取匹配結果會發現 結果爲'aaa'
若是咱們選擇使用非貪婪重複
var reg = new RegExp('a{2,}?');
var str = 'aaa';
reg.exec(str);複製代碼
這時候結果爲 'aa'
,實現非貪婪重複很簡單,在重複後面添加?便可,這時候,正則表達式會盡量少的去匹配重複。
{n, m} -> {n, m}?
{n, } -> {n,}?
{n} -> {n}?
? -> ??
+ -> +?
* -> *?複製代碼
用 |
能夠分割用於選擇的字符,優先級從左向右
ab|cd|ef // 表示 ab 或者 cd 或者 ef複製代碼
()
在包裹子表達式同時將其定義爲子模式
咱們能夠經過 \index
這種寫法在同一個正則表達式中調用子模式, index
表示子模式的索引,從1開始。
var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
// reg1 與 reg2 是兩個基本等價的正則直接量
var str = 'javascript and java';
reg1.test(str); // true
reg2.test(str); // true複製代碼
子模式還有助於咱們抽取子表達式匹配結果
把上述例子改成用exec
方法而且打印
var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
var str = 'javascript and java';
console.log(reg1.exec(str));
console.log(reg2.exec(str));複製代碼
輸出結果爲:
index
的索引會從1開始,由於0是完整的正則匹配結果。
固然,JavaScript容許咱們在使用子表達式的時候不生成子模式
使用(?: )
來包裹子表達式
var reg = /(?:java)script and java/;複製代碼
此時咱們沒法經過\1
找到其子模式,也沒法獲取其子模式的匹配結果。
^ // 字符串開始位置(在字符類中表示取反)
$ // 字符串的結束位置
\b // 單詞邊界,也就是\w與\W的邊界
(?=p) // 要求字符串與p匹配,可是結果集並不包含匹配p的字符
(?!p) // 要求字符串不與p匹配複製代碼
^ 與 $
/^javascript/ // 字符串以javascript開始
/javascript$/ // 字符串以javascript結束複製代碼
\b
var reg = /\bjava\b/;
var str1 = 'java';
var str2 ='javascript';
var str3 = 'java c++';
var str4 = 'html java c++';
reg.test(str1); // true
reg.test(str2); // false
reg.test(str3); // true
reg.test(str4); // true
在這裏 \b 匹配非\w字符,包括字符串起始與結束。
\B與之相反,匹配非單詞邊界處複製代碼
(?=)
var reg = /java(?=script)/;
var str = 'java';
var str1 = 'javascript';
reg.exec(str); // 匹配失敗 , 由於不包含script
reg.exec(str1); // 此時匹配成公,可是匹配結果並不包含script複製代碼
輸出結果爲:
var reg = /java(?!script)/;
var str = 'javaee';
var str1 = 'javascript';
reg.exec(str); // 匹配成功,匹配結果爲java
reg.exec(str1); // 匹配失敗,由於包含script複製代碼
i // 不區分大小寫
m // 匹配多行(使用^ $指定起止時候能通融\n換行)
g // 匹配成功第一處,並不會繼續中止,會繼續尋找全部匹配複製代碼
經過直接量建立正則對象添加修飾符: /java/gim
(使用多個修飾詞直接並列)
經過構造函數建立正則對象添加修飾符: new RegExp(reg , 'gim');
經過String的模式匹配
String對象提供四種方法用於正則匹配。
str.search(reg)
匹配成功返回起始位置,失敗返回-1
,在search
方法中修飾詞g
不生效
var str = 'hello java';
str.search(/java/); // 6
str.search(/^java/); // -1複製代碼
str.match(reg)
匹配失敗返回null
,匹配成功返回的是一個由匹配結果組成的數組。若是該正則 表達式設置了修飾符g
,則該方法返回的數組包含字符串中的全部匹配結果。
var str = 'hello java and javascript';
str.match(/java/);
str.match(/java/g);複製代碼
輸出結果爲:
兩種調用方式,第二個參數不一樣
str.replace(reg , replaceStr)
var str = 'javaee javaee';
// str1 = 'javascript javaee'
var str1 = str.replace(/e{2}/ , 'script');
// str2 = 'javascript javascript' 修飾符g表示全局替換
var str2 = str.replace(/e{2}/g , 'script');
// 補充知識點:str 依然是 javaee ,至於緣由,簡單說就是字符串直接量不可改變,字符串全部的有關於值的改變的方法都是return新值。複製代碼
第二個參數replaceStr,用於替換的字符串有一些特殊的寫法
var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , '「$1」');
console.log(str1) // 「java」,「c++」 and 「html」複製代碼
此時,$1
表示子模式([^"]*)
匹配的結果集, 與咱們上一節定義正則表達式中的調用本身的子模式\1
相仿。
一樣,在此處$
還有其餘幾種用法
$index // 就是上述例子中的$1
$& // 表示原字符串 -> "java","c++" and "html"
$` // 匹配字符串的左側值,在上述例子中匹配成功三次,分別爲: 空值 、 "java", 、"java","c++" and $' // 匹配字符串的右側值,在上述例子中匹配成功三次,分別爲: ,"c++" and "html" 、 and "html" 、空值 $$ // 字符常量$複製代碼
str.replace(reg , function)
var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , function (...arr) {
console.log(arr)
});複製代碼
輸出結果爲:
匹配成功了三次,因此輸出了三次arr
數組,這個數組裏面的元素分別爲:0
: 匹配結果...
: 若存在子模式,這裏爲子模式匹配結果last - 1
: 索引位置last
: 原字符串
咱們能夠根據本身想要的結果,動態替換內容,經過return
將結果替換到新的字符串中。
var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
var str = '"java","c++" and "html"';
var str1 = str.replace(reg , function (...arr) {
return `「${arr[1]}」`
});
console.log(str1) // 「java」,「c++」 and 「html」複製代碼
str.split(分隔符)
str.split(reg)
var str = 'a,b-c,e,f-g';
var arr = str.split(/[,-]/);
console.log(arr) // ['a','b','c','d','e','f','g']複製代碼
經過RegExp的模式匹配
var reg = new RegExp('\\w'); // 經過正則表達式字符串
var reg1 = new RegExp(/\w/); // 經過正則表達式直接量
var reg2 = new RegExp(reg , 'gim'); // 第二個參數爲修飾符複製代碼
source
: String
正則表達式文本值global
: Boolean
是否攜帶全局修飾符g
ignoreCase
:Boolean
是否攜帶忽略大小寫修飾符i
multiline
:Boolean
是否攜帶匹配多行修飾符m
lastIndex
: Number
若是global === true
, 那麼這個參數記錄每次匹配後的索引位置,下面的test
和exec
方法會用到reg.exec(str)
null
,匹配成功,返回匹配結果,每次執行僅返回一個匹配結果,若global === true
,每次匹配成功後,會把lastIndex
屬性設置爲緊挨着 匹配子串的字符位置。再次調用此方法,會從當前位置開始匹配(當咱們使用同一個RegExp
匹配新的字符串的時候,最好把lastIndex
屬性設置爲0)var reg = new RegExp('java' , 'g');
var str = 'javascript java javaee';
var result = reg.exec(str);
while (result) {
console.log(result)
console.log(`lastIndex = ${reg.lastIndex}`)
result = reg.exec(str);
}複製代碼
輸出結果爲:當咱們經過正則表達式直接量來調用進行正則運算的時候,並不會出現這種狀況,那是由於在ES5中,每次經過直接量進行正則運算,JavaScript都會生成新的RegExp
對象。
reg.test(str)
test
方法與exec
基本等價,不一樣的是他們的返回值,test比較簡單粗暴,當exec
返回null
時候,它返回false
,其餘狀況返回true