正則擴(kuò)展

RegExp 構(gòu)造函數(shù)

在 ES5 中,RegExp構(gòu)造函數(shù)的參數(shù)有兩種情況。

第一種情況是,參數(shù)是字符串,這時(shí)第二個(gè)參數(shù)表示正則表達(dá)式的修飾符(flag)。

var regex = new RegExp('xyz', 'i');
// 等價(jià)于
var regex = /xyz/i;

第二種情況是,參數(shù)是一個(gè)正則表示式,這時(shí)會(huì)返回一個(gè)原有正則表達(dá)式的拷貝。

var regex = new RegExp(/xyz/i);
// 等價(jià)于
var regex = /xyz/i;

但是,ES5 不允許此時(shí)使用第二個(gè)參數(shù)添加修飾符,否則會(huì)報(bào)錯(cuò)。

var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another

ES6 改變了這種行為。如果RegExp構(gòu)造函數(shù)第一個(gè)參數(shù)是一個(gè)正則對(duì)象,那么可以使用第二個(gè)參數(shù)指定修飾符。而且,返回的正則表達(dá)式會(huì)忽略原有的正則表達(dá)式的修飾符,只使用新指定的修飾符。

new RegExp(/abc/ig, 'i').flags
// "i"

上面代碼中,原有正則對(duì)象的修飾符是ig,它會(huì)被第二個(gè)參數(shù)i覆蓋。

字符串的正則方法

字符串對(duì)象共有 4 個(gè)方法,可以使用正則表達(dá)式:match()、replace()、search()和split()。

ES6 將這 4 個(gè)方法,在語(yǔ)言內(nèi)部全部調(diào)用RegExp的實(shí)例方法,從而做到所有與正則相關(guān)的方法,全都定義在RegExp對(duì)象上。

String.prototype.match 調(diào)用 RegExp.prototype[Symbol.match]
String.prototype.replace 調(diào)用 RegExp.prototype[Symbol.replace]
String.prototype.search 調(diào)用 RegExp.prototype[Symbol.search]
String.prototype.split 調(diào)用 RegExp.prototype[Symbol.split]

u 修飾符

ES6 對(duì)正則表達(dá)式添加了u修飾符,含義為“Unicode 模式”,用來(lái)正確處理大于\uFFFF的 Unicode 字符。也就是說(shuō),會(huì)正確處理四個(gè)字節(jié)的 UTF-16 編碼。

/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true

上面代碼中,\uD83D\uDC2A是一個(gè)四個(gè)字節(jié)的 UTF-16 編碼,代表一個(gè)字符。但是,ES5 不支持四個(gè)字節(jié)的 UTF-16 編碼,會(huì)將其識(shí)別為兩個(gè)字符,導(dǎo)致第二行代碼結(jié)果為true。加了u修飾符以后,ES6 就會(huì)識(shí)別其為一個(gè)字符,所以第一行代碼結(jié)果為false。

一旦加上u修飾符號(hào),就會(huì)修改下面這些正則表達(dá)式的行為。

(1)點(diǎn)字符

點(diǎn)(.)字符在正則表達(dá)式中,含義是除了換行符以外的任意單個(gè)字符。對(duì)于碼點(diǎn)大于0xFFFF的 Unicode 字符,點(diǎn)字符不能識(shí)別,必須加上u修飾符。

var s = '??';

/^.$/.test(s) // false
/^.$/u.test(s) // true

上面代碼表示,如果不添加u修飾符,正則表達(dá)式就會(huì)認(rèn)為字符串為兩個(gè)字符,從而匹配失敗。

(2)Unicode 字符表示法

ES6 新增了使用大括號(hào)表示 Unicode 字符,這種表示法在正則表達(dá)式中必須加上u修飾符,才能識(shí)別當(dāng)中的大括號(hào),否則會(huì)被解讀為量詞。

/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('??') // true

上面代碼表示,如果不加u修飾符,正則表達(dá)式無(wú)法識(shí)別\u{61}這種表示法,只會(huì)認(rèn)為這匹配 61 個(gè)連續(xù)的u。

(3)量詞

使用u修飾符后,所有量詞都會(huì)正確識(shí)別碼點(diǎn)大于0xFFFF的 Unicode 字符。

/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/??{2}/.test('????') // false
/??{2}/u.test('????') // true

(4)預(yù)定義模式

u修飾符也影響到預(yù)定義模式,能否正確識(shí)別碼點(diǎn)大于0xFFFF的 Unicode 字符。

/^\S$/.test('??') // false
/^\S$/u.test('??') // true

上面代碼的\S是預(yù)定義模式,匹配所有非空白字符。只有加了u修飾符,它才能正確匹配碼點(diǎn)大于0xFFFF的 Unicode 字符。

利用這一點(diǎn),可以寫(xiě)出一個(gè)正確返回字符串長(zhǎng)度的函數(shù)。(可以用來(lái)做字符長(zhǎng)度驗(yàn)證)

function codePointLength(text) {
  var result = text.match(/[\s\S]/gu);
  return result ? result.length : 0;
}

var s = '????';

s.length // 4
codePointLength(s) // 2

(5)i 修飾符

有些 Unicode 字符的編碼不同,但是字型很相近,比如,\u004B與\u212A都是大寫(xiě)的K。

/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true

上面代碼中,不加u修飾符,就無(wú)法識(shí)別非規(guī)范的K字符。

(6)轉(zhuǎn)義

沒(méi)有u修飾符的情況下,正則中沒(méi)有定義的轉(zhuǎn)義(如逗號(hào)的轉(zhuǎn)義,)無(wú)效,而在u模式會(huì)報(bào)錯(cuò)。

/\,/ // /\,/
/\,/u // 報(bào)錯(cuò)

上面代碼中,沒(méi)有u修飾符時(shí),逗號(hào)前面的反斜杠是無(wú)效的,加了u修飾符就報(bào)錯(cuò)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容