ES9(ES2018)中的正則表達式

ES9中正則表達式相關主要有兩個提案:正則表達式命名捕獲組 & 正則表達式dotAll模式,目前都已進入stage4階段。html

正則表達式命名捕獲組

ECMAScript提案「正則表達式命名捕獲組」proposal-regexp-named-group 由 Gorkem Yakin, Daniel Ehrenberg負責。java

1. 什麼是捕獲組

捕獲組就是把正則表達式中子表達式匹配的內容,保存到內存中以數字編號或顯示命名的組裏,方便後面引用,且這種引用既能夠在正則表達式內部,也能夠在正則表達式外部。git

捕獲組有兩種形式,一種是普通捕獲組,另外一種是命名捕獲組。github

目前JavaScript只支持數字形式的普通捕獲組,而這個提案就是爲了給JavaScript增長命名捕獲組。正則表達式

2.捕獲組編號規則

編號規則指的是以數字爲捕獲組進行編號的規則, 編號0的捕獲組表明正則表達式總體。babel

const regex = /(\d{4})-(\d{2})-(\d{2})/;
const matchers = regex.exec('2020-12-02');
console.table(matchers)

image.png

3.命名捕獲組

使用數字捕獲組的一個缺點是對於引用不太直觀。好比上面的例子,咱們相對比較難分清楚哪一個組表明年,哪一個組表明月或者日。並且,當咱們交互了年和月的值時,使用捕獲組引用的代碼都須要更改。app

而命名捕獲組就是爲了解決這個問題。函數

命名捕獲組可使用(?<name>...)語法給每一個組起個名稱。所以,用來匹配日期的正則表達式能夠寫爲:spa

/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/

每一個捕獲組的名字必須惟一,不然會拋出異常:
image.png
另外,捕獲組的名字必須符合JavaScript命名規範:
image.pngprototype

命名捕獲組能夠經過匹配結果的groups 屬性訪問。

let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let result = regx.exec('2020-12-02');

result.groups.year === '2020';
result.groups.month === '12';
result.groups.day === '02';

result[0] === '2020-12-02';
result[1] === '2020';
result[2] === '12';
result[3] === '02';

使用解構賦值的例子:

let regx = /^(?<one>.*):(?<two>.*)$/;
let {groups: {one, two}} = regx.exec('foo:bar');
console.log(`one: ${one}, two: ${two}`);

4.反向引用

當須要在正則表達式裏面引用命名捕獲組時,使用\k<name>語法。

let duplicate = /^(?<half>.*).\k<half>$/;
duplicate.test('a*b'); // false
duplicate.test('a*a'); // true

若是引用一個不存在的命名捕獲組,會拋出異常:
image.png
命名捕獲組也能夠和普通數字捕獲組一塊兒使用:

let triplicate = /^(?<part>.*).\k<part>.\1$/;
triplicate.test('a*a*a'); // true
triplicate.test('a*a*b'); // false

5.替換

命名捕獲組也能夠在String.prototype.replace函數中引用,使用$<name>語法。

let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
let result = "2020-12-02".replace(regx, '$<day>/$<month>/$<year>');

console.log(result === '02/12/2020');

String.prototype.replace第2個參數能夠接受一個函數。這時,命名捕獲組的引用會做爲 groups參數傳遞進取。

第2個參數的函數簽名是function (matched, capture1, ..., captureN, position, S, groups)

let regx = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

let result = '2020-12-02'.replace(regx, (...args)=>{
    let { day, month, year } = args[args.length - 1];
    return `${day}/${month}/${year}`
});

result === '02/12/2020';

6.命名捕獲組未匹配

若是一個可選的命名捕獲組沒有匹配時,在匹配結果中,此命名組依然存在,值是undefined

let regx = /^(?<optional>\d+)?$/;
let matchers = regx.exec('');

matcher[0] === '';
matchers.groups.optional === undefined;

若是捕獲組不是可選的,匹配結果是null

let regx = /^(?<foo>\d+)$/;
let matchers = regx.exec('');

matchers === null;

7. 向下兼容

/(?<name>)//\k<name>/只有在命名捕獲組中才有意義。若是正則表達式沒有命名捕獲組,那麼/\k<name>/僅僅是字符串字面量"k<name>"而已。

8. 實現

正則表達式dotAll模式

相關文章
相關標籤/搜索