自從年前得空寫了兩篇文章之后就開始忙了,這一忙就是2個月??。當時信誓旦旦說的定期寫篇博客的計劃也就泡湯了??,不過好在最近有空,順便總結一下這兩個月遇到的幾個問題。第一個問題就是項目中用到了一些正則才發現之前被自己忽略的正則是時候補一補了。恰逢今天周六??,就把自己學習JavaScript正則表達式的筆記整理成文,寫了這篇關于正則表達式理論基礎的文章,希望本文能對有需要的同學提供幫助。號外:本文相對基礎,大神請忽略??。
一. 基本概念
正則表達式是用于匹配字符串中字符組合的模式。 一種幾乎可以在所有的程序設計語言里和所有的計算機平臺上使用的文字處理工具。它可以用來查找(搜索)特定的信息,也可以用來查找并編輯(替換)特定的信息。
核心是匹配,匹配位置或者匹配字符。
在
JavaScript
中,正則表達式也是對象。這些模式被用于
RegExp
的exec
和test
方法, 以及String
的match
、replace
、search
和split
方法。
二. 創建正則表達式
2.1 正則表達式的創建可以有以下三種方法。
2.1.1 字面量
/pattern/flags
let reg1 = /jing ke tong xue/g;
console.log(reg1); // /jing ke tong xue/g
2.1.2 構造函數
new RegExp(pattern [, flags])
let reg2 = new RegExp('jing ke tong xue', 'g');
console.log(reg2); // /jing ke tong xue/g
2.1.3 工廠符號
RegExp(pattern [, flags])
let reg3 = RegExp('jing ke tong xue', 'g');
console.log(reg3); // /jing ke tong xue/g
2.2 字面量、構造函數、工廠符號在創建正則表達式中的異同
2.2.1 共同點
三種方法都可以創建正則表達式,正則表達式的文本pattern
為必須參數,標志符flags
有g、i、m、y、u
五個可選、可任意搭配參數。
2.2.2 不同點
構造函數和工廠符號除了相差一個
new
關鍵字外沒有什么不同,但是不推薦工廠符號的形式創建正則表達式。下面主要說一下字面量和構造函數的形式創建正則表達式的不同之處。
當表達式被賦值時,字面量形式提供正則表達式的
編譯(compilation)
狀態,當正則表達式保持為常量時使用字面量。例如當你在循環中使用字面量構造一個正則表達式時,正則表達式不會在每一次迭代中都被重新編譯(recompiled)
。正則表達式對象的構造函數,如
new RegExp('jing ke tong xue')
提供了正則表達式運行時編譯(runtime compilation)
。如果你知道正則表達式模式將會改變,或者你事先不知道什么模式,而是從另一個來源獲取,如用戶輸入,這些情況都可以使用構造函數。從
ECMAScript 6
開始,當第一個參數為正則表達式而第二個標志參數存在時,new RegExp(/jing ke tong xue/, 'g')
不再拋出==TypeError== (“當從其他正則表達式進行構造時不支持標志”)的異常,取而代之,將使用這些參數創建一個新的正則表達式。字面量方式
pattern
中所有字符都是元字符,所以不能進行變量值的拼接。通過構造函數的方式pattern
中所有字符都是字符串,是可以進行字符串拼接的,同時對于特殊字符也是需要轉義的。
- 字符串變量拼接
const name = 'jing ke';
// 字符串拼接不會成功
let reg1 = /" + name + " tong xue/g;
console.log(reg1); // /" + name + " tong xue/g
// 字符串拼接可以成功
let reg2 = new RegExp(name + ' tong xue', 'g');
console.log(reg2); // /jing ke tong xue/g
- 特殊字符轉義
const name = 'jing ke';
// 匹配name,這里jing和ke之間可能有1個或多個空格
let reg1 = /jing\s+ke/g;
console.log(reg1); // /jing\s+ke/g
console.log(reg1.test(name)); // true
// 這里創建的正則表達式和字面量方式創建的結果并不一樣
let reg2 = new RegExp('jing\s+ke', 'g');
console.log(reg2); // /jings+ke/g
console.log(reg2.test(name)); // false
// 這里我把reg3稍稍改造了一下,結果就和reg1一樣了
let reg3 = new RegExp('jing\\s+ke', 'g');
console.log(reg3); // /jing\s+ke/g
console.log(reg3.test(name)); // true
再看一個特殊字符轉義的例子
// 寫一個正則表達式匹配反斜杠 \
const str = '\\'; // 這里str就是 \,反斜杠有特殊意義,下文介紹基本元字符會講
// 字面量方式
let reg1 = /\\/g;
console.log(reg1); // /\\/g
console.log(reg1.test(str)); // true
// 為什么是4個反斜杠,詳見下文元字符介紹。自己在控制臺試試1個,2個,3個會報什么錯
let reg2 = new RegExp('\\\\', 'g');
console.log(reg2); // /\\/g
console.log(reg2.test(str)); // true
三. 正則表達式中特殊字符
3.1 標志字符
標志字符 | 含義 |
---|---|
g | 全局匹配,找到所有匹配,而不是在第一個匹配后停止。 |
i | 忽略大小寫。 |
m | 多行,將開始和結束字符(^和$)視為在多行上工作(也就是,分別匹配每一行的開始和結束(由 \n 或 \r 分割),而不只是只匹配整個輸入字符串的最開始和最末尾處。 |
u | ES6新增,Unicode,將模式視為Unicode序列點的序列。 |
y | ES6新增,粘性匹配,僅匹配目標字符串中此正則表達式的lastIndex屬性指示的索引(并且不嘗試從任何后續的索引匹配)。 |
3.2 基本元字符
基本元字符 | 含義 |
---|---|
. | 匹配除了換行符之外的任何單個字符 |
\ | 在非特殊字符之前的反斜杠表示下一個字符是特殊的,不能從字面上解釋。例如,沒有前\ 的b 通常匹配小寫b ,無論它們出現在哪里。如果加了\ ,這個字符變成了一個特殊意義的字符,反斜杠也可以將其后的特殊字符,轉義為字面量。例如,模式 /a*/ 代表會匹配0個或者多個a。相反,模式 /a\*/ 將* 的特殊性移除,從而可以匹配像 a* 這樣的字符串。 |
邏輯或操作符。 | |
[...] | 定義一個字符集合,匹配字符集合中的一個字符,在字符集合里面像 . ,\ 這些字符都表示其本身。 |
[^...] | 對上面一個集合取非。 |
- | 定義一個區間,例如[A-Z],其首尾字符在 ASCII 字符集里面。 |
3.3 數量元字符
量詞 | 含義 |
---|---|
* | 等價于{0,} ,表示出現任意次,可以不出現。 |
+ | 等價于{1,} ,表示至少出現一次,上不封頂。 |
? | 等價于{0, 1} 表示出現一次或零次。 |
{m} | 等價于{m, m} ,標志正好出現m 次,不能多也不能少。 |
{m,} | 表示至少出現 m 次,上不封頂。 |
量詞后面加
?
可以實現惰性匹配,對應關系如下:
貪婪量詞 | 惰性量詞 |
---|---|
* | *? |
+ | +? |
? | ?? |
{m} | {m}? |
{m,} | {m,}? |
3.4 錨字符(位置元字符)
字符 | 含義 |
---|---|
^ | 單獨使用匹配表達式的開始。匹配字符串的開頭,在多行檢索中,匹配一行的開頭。 |
$ | 匹配表達式的結束。匹配字符串的結尾,在多行檢索中,匹配一行的結尾。 |
\b | 匹配一個單詞的邊界,簡而言之,就是位于字符\w和字符\W 之間的位置,或位于字符\w 和字符串的開頭或結尾之間的位置(但需要注意的是在字符組內[\b] 匹配的是退格符)。 |
\B | 匹配非單詞邊界。 |
(?=p) | 匹配 p 前面的位置。零寬正向先行斷言,要求接下來的字符都與p 匹配,但不能包括匹配p的那些字符。 |
(?!p) | 匹配不是 p 前面的位置。零寬負向先行斷言,要求接下來的字符不與p 匹配。 |
3.5 特殊元字符
字符 | 含義 |
---|---|
\d | 等價于[0-9] ,表示一位數字s。 |
\D | 等價于[^0-9] ,表示一位非數字。除了ASCⅡ數字之外的任何字符。 |
\s | 等價于[\t\v\n\r\f] ,表示空白符,包括空格,水平制表符(\t) ,垂直制表符(\v) ,換行符(\n ),回車符(\r) ,換頁符(\f) 。 |
\S | 等價于[^\t\v\n\r\f] ,表示非空白符。 |
\w | 等價于[0-9a-zA-Z] ,表示數字大小寫字母和下劃線。 |
\W | 等價于[^0-9a-zA-Z] ,表示非單詞字符。 |
四. 正則表達式的一些屬性
4.1 RegExp.lastIndex
lastIndex
是正則表達式的一個可讀可寫的整型屬性,用來指定下一次匹配的起始索引。只有正則表達式使用了表示全局檢索的 "g" 標志時,該屬性才會起作用。
如果 lastIndex 大于字符串的長度,則
regexp.test
和regexp.exec
將會匹配失敗,然后 lastIndex 被設置為 0。
如果 lastIndex 等于字符串的長度,且該正則表達式匹配空字符串,則該正則表達式匹配從 lastIndex 開始的字符串。
如果 lastIndex 等于字符串的長度,且該正則表達式不匹配空字符串 ,則該正則表達式不匹配字符串,lastIndex 被設置為 0。
否則,lastIndex 被設置為緊隨最近一次成功匹配的下一個位置。
請看如下示例代碼:
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue jing ke tong xue';
let reg = /jing ke tong xue/g;
// lastIndex從0開始
console.log(reg.lastIndex); // 0
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 16
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 33
// lastIndex可修改
reg.lastIndex = 0;
console.log(reg.lastIndex); // 0
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 16
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 33
console.log(reg.test(str)); // false
console.log(reg.lastIndex); // 50
console.log(reg.test(str));// true
console.log(reg.lastIndex); // 67
console.log(reg.test(str));// false
// 上一次匹配失敗,lastIndex重置為0
console.log(reg.lastIndex); // 0
console.log(reg.test(str));// true
4.2 RegExp.prototype.global
global
屬性表明正則表達式是否使用了 "g" 標志。global
的值是布爾對象,如果使用了 "g" 標志,則返回true
;否則返回false
。 "g" 標志意味著正則表達式應該測試字符串中所有可能的匹配。global
是一個正則表達式實例的只讀屬性。RegExp.prototype.global
的writable
、enumerable
、configurable
屬性均為false
,無法直接更改此屬性。
請看如下示例代碼:
let reg1 = /jing ke tong xue/;
console.log(reg1.global); // false.
let reg2 = /jing ke tong xue/g;
console.log(reg2.global); // true
4.3 RegExp.prototype.ignoreCase
ignoreCase
屬性表明正則表達式是否使用了 "i" 標志。ignoreCase
的值是布爾對象,如果使用了"i" 標志,則返回true
;否則,返回false
。"i"標志意味著在字符串進行匹配時,應該忽略大小寫。ignoreCase
是正則表達式實例的只讀屬性。RegExp.prototype.ignoreCase
的writable
、enumerable
、configurable
屬性均為false
,無法直接更改此屬性。
請看如下示例代碼:
let reg1 = /jing ke tong xue/;
console.log(reg1.ignoreCase); // false.
let reg2 = /jing ke tong xue/i;
console.log(reg2.ignoreCase); // true
4.4 RegExp.prototype.multiline
multiline
屬性表明正則表達式是否使用了 "m" 標志。multiline
的值是布爾對象,如果使用了"m" 標志,則返回true
;否則,返回false
。"m" 標志意味著一個多行輸入字符串被看作多行。multiline
是正則表達式實例的一個只讀屬性。RegExp.prototype.multiline
的writable
、enumerable
、configurable
屬性均為false
,無法直接更改此屬性。
請看如下示例代碼:
let reg1 = /jing ke tong xue/;
console.log(reg1.multiline); // false.
let reg2 = /jing ke tong xue/m;
console.log(reg2.multiline); // true
4.5 RegExp.prototype.unicode
unicode
屬性表明正則表達式帶有"u" 標志。unicode
的值是Boolean,并且如果使用了 "u" 標志則為true
;否則為false
。"u" 標志開啟了多種Unicode相關的特性。使用 "u" 標志,任何Unicode 代碼點的轉義都會被解釋。unicode
是正則表達式獨立實例的只讀屬性。RegExp.prototype.unicode
的writable
、enumerable
屬性為false
,configurable
屬性均為true
,無法直接更改此屬性。
請看如下示例代碼:
let reg1 = /jing ke tong xue/;
console.log(reg1.unicode); // false.
let reg2 = /jing ke tong xue/u;
console.log(reg2.unicode); // true
再看如下示例代碼:
// 定義一個四個字節的 UTF-16 編碼的字符
const str = '\uD83D\uDC2A';
let reg1 = /^\uD83D/;
// ES5不支持四個字節的 UTF-16 編碼,會將其識別為兩個字符,故而輸出 true
console.log(reg1.test(str)); // true
let reg2 = /^\uD83D/u;
// 加了u修飾符以后,ES6 就會識別其為一個字符,故而輸出false
console.log(reg2.test(str)); // false
4.6 RegExp.prototype.sticky
sticky
屬性表明正則表達式帶有"y" 標志。sticky
的值是Boolean
,并且如果使用了"y"標志則為true
;否則為false
。"y" 標志指示搜索是否具有粘性,僅從正則表達式的lastIndex 屬性表示的索引處為目標字符串匹配(并且不會嘗試從后續索引匹配)。sticky
是正則表達式獨立實例的只讀屬性。RegExp.prototype.sticky
的writable
、enumerable
屬性為false
,configurable
屬性均為true
,無法直接更改此屬性。
請看如下示例代碼:
let reg1 = /jing ke tong xue/;
console.log(reg1.sticky); // false.
let reg2 = /jing ke tong xue/y;
console.log(reg2.sticky); // true
再看如下示例代碼:
const str = 'test jing ke tong xue test jing ke tong xue';
let reg1 = /jing ke tong xue/;
// 沒有y標識符,lastIndex始終為0,但是reg1并不具有粘性,并不從lastIndex號為開始
console.log(reg1.lastIndex); // 0
console.log(reg1.test(str)); // true
reg1.lastIndex = 5;
console.log(reg1.lastIndex); // 5
console.log(reg1.test(str)); // true
// 由于沒有y標識符,在正則表達式匹配之后,lastIndex又被重置為0
console.log(reg1.lastIndex); // 0
console.log(reg1.test(str)); // true
let reg2 = /jing ke tong xue/y;
// 第一次匹配將從0號位開始
console.log(reg2.lastIndex); // 0
console.log(reg2.test(str)); // false
// 第二次一次匹配將從5號位開始
reg2.lastIndex = 5;
console.log(reg2.lastIndex); // 5
console.log(reg2.test(str)); // true
// 下一次匹配將從21號位開始
console.log(reg2.lastIndex); // 21
console.log(reg2.test(str)); // false
// 上一次匹配失敗,lastIndex重置為0;下一次匹配將從0號位開始
console.log(reg2.lastIndex);
4.7 RegExp.prototype.source
-
source
屬性返回一個值為當前正則表達式對象的模式文本的字符串。該字符串不會包含正則字面量兩邊的斜杠以及任何的標志字符。
請看如下示例代碼:
let reg = /jing ke tong xue/gimuy;
console.log(reg.source); // jing ke tong xue
// source無法被修改,不會生效
reg.source = 'tong xue jing ke';
console.log(reg); // /jing ke tong xue/gimuy
4.8 RegExp.prototype.flags
flags
為ES6
新增屬性,返回一個由當前正則表達式對象的標志組成的字符串。標志以字母表順序排序。(從左到右
gimuy
)。flags
是正則表達式獨立實例的只讀屬性。RegExp.prototype.flags
的writable
、enumerable
屬性為false
,configurable
屬性均為true
,無法直接更改此屬性。
請看如下示例代碼:
let reg = /jing ke tong xue/gimuy;
console.log(reg.flags); // jing ke tong xue
// flags無法被修改,不會生效
reg.flags = 'g';
console.log(reg); // /jing ke tong xue/gimuy
flags屬性為ES6新增屬性,ES6以前可用如下Polyfill。
if (RegExp.prototype.flags === undefined) {
Object.defineProperty(RegExp.prototype, 'flags', {
writable: false, // 默認為false,寫上便于理解
enumerable: false, // 默認為false,寫上便于理解
configurable: true,
get: function() {
return this.toString().match(/[gimuy]*$/)[0];
}
});
}
五. 正則表達式的一些方法
5.1 RegExp.prototype.test
語法
reg.test(str)
。str
:用來與正則表達式匹配的字符串。test()
方法執行一個檢索,用來查看正則表達式與指定的字符串是否匹配。如果正則表達式與指定的字符串匹配 ,返回
true
,否則false
。
const str = 'jing ke tong xue';
let reg1 = /^jing/;
// 判斷str是不是以jing開頭
console.log(reg1.test(str)); // true
let reg2 = /^ke/;
// 判斷str是不是以ke開頭
console.log(reg2.test(str)); // fase
在設置有全局標志g
的正則使用test方法。
如果正則表達式設置了全局標志,test方法的執行會改變正則表達式的 lastIndex 屬性。連續的執行test方法,后續的執行將會從 lastIndex 處開始匹配字符串。如果 test 方法返回匹配失敗 false,lastIndex 屬性將會被重置為0。
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue';
let reg = /jing ke/g;
console.log(reg.lastIndex); // 0
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 7
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 24
console.log(reg.test(str)); // true
console.log(reg.lastIndex); // 41
console.log(reg.test(str)); // false
console.log(reg.lastIndex); // 0
5.2 RegExp.prototype.exec
語法
reg.exec(str)
。str
:要匹配正則表達式的字符串。exec()
方法在一個指定字符串中執行一個搜索匹配。返回一個結果數組或null
。如果匹配成功,
exec()
方法返回一個數組,并更新正則表達式對象的屬性。返回的數組將完全匹配成功的文本作為第一項,將正則括號里匹配成功的作為數組填充到后面。如果匹配失敗,
exec()
方法返回null
。
??如果你只是需要第一個匹配結果,你可能想要使用 RegExp.exec() 。
??如果你想要獲得捕獲組,并且設置了全局標志,你需要用 String.prototype.match() 。
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue';
let reg = /jing ke/g;
console.log(reg.lastIndex); // 0
console.log(reg.exec(str)); // ["jing ke", index: 0, input: "jing ke tong xue jing ke tong xue jing ke tong xue", groups: undefined]
console.log(reg.lastIndex); // 7
console.log(reg.exec(str)); // ["jing ke", index: 17, input: "jing ke tong xue jing ke tong xue jing ke tong xue", groups: undefined]
console.log(reg.lastIndex); // 24
console.log(reg.exec(str)); // ["jing ke", index: 34, input: "jing ke tong xue jing ke tong xue jing ke tong xue", groups: undefined]
console.log(reg.lastIndex); // 41
console.log(reg.exec(str)); // null
console.log(reg.lastIndex); // 0
從上述代碼看出,在使用exec時,經常需要配合使用while循環使用:
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue';
let reg = /jing ke/g;
let result;
// 當reg.exec(str)返回null時結束循環,與上面代碼結果一致
while (result = reg.exec(str)) {
console.log(`result: ${result}`, `\nindex: ${result.index}`, `\nlastIndex: ${reg.lastIndex}`, `\ninput: ${result.input}`);
}
// result: jing ke
// index: 0
// lastIndex: 7
// input: jing ke tong xue jing ke tong xue jing ke tong xue
// index.html:132 result: jing ke
// index: 17
// lastIndex: 24
// input: jing ke tong xue jing ke tong xue jing ke tong xue
// index.html:132 result: jing ke
// index: 34
// lastIndex: 41
// input: jing ke tong xue jing ke tong xue jing ke tong xue
5.2 RegExp.prototype.toString
語法
reg.toString()
toString()
返回一個表示該正則表達式的字符串。RegExp
對象覆蓋了Object
對象的toString()
方法,并沒有繼承Object.prototype.toString()
。對于RegExp
對象,toString()
方法返回一個該正則表達式的字符串形式,同時會將flags屬性按照字母表順序重排。
let reg = /jing ke tong xue/yguim;
console.log(reg.toString()); // /jing ke tong xue/gimuy
六. 4種適用于模式匹配的String方法
這里介紹的4種String方法只是和模式匹配相關的內容,與模式匹配不相關的內容下面并不會提及,如果想了解更多請移步這里。
6.1 String.prototype.search
- 語法
str.search(regexp)
。
regexp
:一個正則表達式(regular expression
)對象。如果傳入一個非正則表達式對象,則會使用new RegExp(obj)
隱式地將其轉換為正則表達式對象。
search()
方法執行正則表達式和 String對象之間的一個搜索匹配。當你想要知道字符串中是否存在某個模式(pattern
)時可使用search
,類似于正則表達式的test
方法。如果匹配成功,則 search() 返回正則表達式在字符串中首次匹配項的索引。否則,返回 -1。
??如果你需要知道一個字符串是否匹配一個正則表達式
RegExp
,可使用search()
。
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue jing ke tong xue';
let reg = /jing ke tong xue/g;
console.log(str.search(reg)); // 0
// 由于條件判斷的時候喜歡用true或false, 改造如下, 詳情請自行學習JavaScript位(~)運算符
console.log(!!~str.search(reg)); // true
6.2 String.prototype.match
- 語法
str.match(regexp)
。
regexp
:一個正則表達式對象。如果傳入一個非正則表達式對象,則會隱式地使用new RegExp(obj)
將其轉換為一個RegExp
。如果你未提供任何參數,直接使用match()
,那么你會得到一個包含空字符串的Array :[""]
。
當一個字符串與一個正則表達式匹配時,
match()
方法檢索匹配項。如果正則表達式不包含g
標志,則str.match()
會返回和RegExp.exec()
相同的結果。而且返回的Array
擁有一個額外的input
屬性,該屬性包含被解析的原始字符串。另外,還擁有一個 index 屬性,該屬性表示匹配結果在原字符串中的索引(以0開始)。如果正則表達式包含
g
標志,則該方法返回一個Array
,它包含所有匹配的子字符串而不是匹配對象。捕獲組不會被返回(即不返回index
屬性和input
屬性)。如果沒有匹配到,則返回null
。
在下例中,使用 match
查找 "March" 緊跟著 1 個或多個數值字符,再緊跟著一個逗號“,”,再緊跟著一個或多個空格,接著跟著4個數值字符。正則表達式包含 i 標志,因此大小寫會被忽略。第二個包含 g 標志會進行全局匹配。
// 啊,在2018年3月31日的下午,詩性大發,賦詩兩句??
// ??一支穿云箭, 千軍萬馬來相見??
const str = 'In March 31, 2018, An arrow through the clouds to meet thousands upon thousands of horses and soldiers, In March 31, 2018';
let reg1 = /In (march \d+, (\d{4}))/i;
let match1 = str.match(reg1);
console.log(match1);
// 以下是logs內容
// => [
// => "In March 31, 2018",
// => "March 31, 2018",
// => "2018",
// => index: 0,
// => input: "In March 31, 2018, An arrow through the clouds to meet thousands upon thousands of horses and soldiers.",
// => groups: undefined
// => ]
// ??釋疑??
// "In March 31, 2018" 是整個匹配
// "March 31, 2018" 是被(March \d+, (\d*))捕獲的內容
// "2018" 是被(\d{4}) 捕獲的內容
// index: 0 匹配開始的索引
// input: ... 是被解析的原始字符串
// 這個和上面的差別就是flags多了個g標識符
let reg2 = /In (march \d+, (\d{4}))/ig;
let match2 = str.match(reg2);
// 多了一個標識符,返回的結果是一個包含匹配字符的數組
console.log(match2); // ["In March 31, 2018", "In March 31, 2018"]
號外,match
方法除了支持正則表達式對象作為參數外,還支持非正則表達式對象作為參數。
// 這個例子就不給答案了,好記性不如爛筆頭,有心的同學請在控制臺輸出結果查看區別??
const str1 = "NaN means not a number. Infinity contains -Infinity and +Infinity in JavaScript.";
const str2 = "4 is 4, 10 is 10, 14 is 14, 40 is 40.";
const str3 = "The contract was declared null and void.";
console.log(str1.match("number"));
console.log(str1.match("NaN"));
console.log(str1.match(NaN));
console.log(str1.match("Infinity"));
console.log(str1.match(Infinity));
console.log(str1.match(+Infinity));
console.log(str1.match(-Infinity));
console.log(str2.match("10"));
console.log(str2.match(10));
console.log(str2.match("-10"));
console.log(str2.match(-10));
console.log(str2.match("+10"));
console.log(str2.match(+10));
console.log(str3.match("null"));
console.log(str3.match(null));
6.3 String.prototype.split
- 語法
str.split([separator[, limit]])
。
separator
: 指定表示每個拆分應發生的點的字符串。separator 可以是一個字符串或正則表達式。 如果純文本分隔符包含多個字符,則必須找到整個字符串來表示分割點。如果在str中省略或不出現分隔符,則返回的數組包含一個由整個字符串組成的元素。如果分隔符為空字符串,則將str原字符串中每個字符的數組形式返回。
limit
: 一個整數,限定返回的分割片段數量。當提供此參數時,split 方法會在指定分隔符的每次出現時分割該字符串,但在限制條目已放入數組時停止。如果在達到指定限制之前達到字符串的末尾,它可能仍然包含少于限制的條目。新數組中不返回剩下的文本。
split
方法接受兩個參數,返回一個數組。第一個是用來分割字符串的字符或者正則,如果是空字符串則會將元字符串中的每個字符以數組形式返回,第二個參數可選作為限制分割多少個字符,也是返回的數組的長度限制。有一個地方需要注意,用捕獲括號的時候會將匹配結果也包含在返回的數組中。
const str = 'jing ke tong xue jing ke tong xue jing ke tong xue';
let reg1 = /\s/;
console.log(str.split(reg1));
// => ["jing", "ke", "tong", "xue", "jing", "ke", "tong", "xue", "jing", "ke", "tong", "xue"]
console.log(str.split(" "));
// => ["jing", "ke", "tong", "xue", "jing", "ke", "tong", "xue", "jing", "ke", "tong", "xue"]
let reg2 = /\s+(tong)\s+/;
console.log(str.split(reg2));
// => ["jing ke", "tong", "xue jing ke", "tong", "xue jing ke", "tong", "xue"]
let reg3 = /\s+tong\s+/;
console.log(str.split(reg3));
// => ["jing ke", "xue jing ke", "xue jing ke", "xue"]
console.log(str.split(' tong '));
// => ["jing ke", "xue jing ke", "xue jing ke", "xue"]
6.4 String.prototype.replace
該方法并不改變調用它的字符串本身,而只是返回一個新的替換后的字符串。
在進行全局的搜索替換時,正則表達式需包含 g 標志。
- 語法
str.replace(regexp|substr, newSubStr|function)
。
regexp (pattern)
: 一個RegExp 對象或者其字面量。該正則所匹配的內容會被第二個參數的返回值替換掉。
substr (pattern)
: 一個要被 newSubStr 替換的字符串。其被視為一整個字符串,而不是一個正則表達式。僅僅是第一個匹配會被替換。
newSubStr (replacement)
: 用于替換掉第一個參數在原字符串中的匹配部分的字符串。該字符串中可以內插一些特殊的變量名。參考下面的使用字符串作為參數。
function (replacement)
: 一個用來創建新子字符串的函數,該函數的返回值將替換掉第一個參數匹配到的結果。參考下面的指定一個函數作為參數。
replace
方法接受兩個參數,第一個是要被替換的文本,可以是正則也可以是字符串,如果是字符串的時候不會被轉換成正則,而是作為檢索的直接量文本。第二個是替換成的文本,可以是字符串或者函數,字符串可以使用一些特殊的變量來替代前面捕獲到的子串。返回一個部分或全部匹配由替代模式所取代的新的字符串。
如果使用字符串作為參數時替換字符串可以插入下面的特殊變量名:
變量名 | 代表的值 |
---|---|
$$ | 插入一個 "$"。 |
$& | 插入匹配的子串。 |
$` | 插入當前匹配的子串左邊的內容。 |
$' | 插入當前匹配的子串右邊的內容。 |
$n | 假如第一個參數是 RegExp對象,并且 n 是個小于100的非負整數,那么插入第 n 個括號匹配的字符串。 |
如果是函數的話,當匹配執行后, 該函數就會執行。 函數的返回值作為替換字符串。另外要注意的是, 如果第一個參數是正則表達式, 并且其為全局匹配模式, 那么這個方法將被多次調用, 每次匹配都會被調用。
變量名 | 代表的值 |
---|---|
match | 匹配的子串。(對應于上述的$&。) |
p1, p2, ... | 假如replace()方法的第一個參數是一個RegExp 對象,則代表第n個括號匹配的字符串。(對應于上述的$1,$2等。) |
offset | 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是“abcd”,匹配到的子字符串是“bc”,那么這個參數將是1) |
string | 被匹配的原字符串。 |
const str = '2018-03-31';
let reg = /^(\d{4})\D(\d{2})\D(\d{2})$/;
function replacer (match, p1, p2, p3, offset, string) {
console.log([match, p1, p2, p3, offset, string]);
return [p1, p2, p3].join('/')
}
console.log(str.replace(reg, replacer));
// => ["2018-03-31", "2018", "03", "31", 0, "2018-03-31"]
// => 2018/03/31
由于內容比較多,文章寫的太長也不便于閱讀,所以本篇至此結束。后面估計還有兩篇完結,到時候補了再更。
- 第一篇完結(就是本文): JavaScript正則表達式學習筆記(一) - 理論基礎
- 第二篇待更:JavaScript正則表達式學習筆記(二) - 打怪升級
- 第三篇待更:JavaScript正則表達式學習筆記(三) - 終章