自從年前得空寫了兩篇文章之後就開始忙了,這一忙就是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正規表示式學習筆記(三) - 終章