即將推出的規則運算式功能

ES2015 為 JavaScript 語言引進許多新功能,包括使用 Unicode (/u) 和 sticky (/y) 旗標大幅改善規則運算式語法。但自那時起,我們並未停止開發。在與 TC39 (ECMAScript 標準機構) 的其他成員密切合作下,V8 團隊提出並共同設計了幾項新功能,讓規則運算式更強大。

這些功能目前正提案納入 JavaScript 規格。雖然提案尚未完全通過,但已進入 TC39 程序的第 3 階段。我們已在標記 (請見下方) 後方實作這些功能,以便在規格定案前,及時向各個提案作者提供設計和實作意見回饋。

本篇文章將預先介紹這項令人期待的功能。如果您想跟著後續範例操作,請前往 chrome://flags/#enable-javascript-harmony 啟用實驗性 JavaScript 功能。

命名擷取

規則運算式可包含所謂的擷取 (或群組),可擷取部分相符的文字。到目前為止,開發人員只能透過索引參照這些擷取內容,而索引是由擷取內容在模式中的位置決定。

const pattern = /(\d{4})-(\d{2})-(\d{2})/u;
const result = pattern.exec('2017-07-10');
// result[0] === '2017-07-10'
// result[1] === '2017'
// result[2] === '07'
// result[3] === '10'

不過,規則運算式本身就難以閱讀、編寫和維護,而數字參照則會讓情況更加複雜。舉例來說,在較長的模式中,要判斷特定擷取作業的索引可能會很困難:

/(?:(.)(.(?<=[^(])(.)))/  // Index of the last capture?

更糟的是,模式的變更可能會導致所有現有擷取內容的索引偏移:

/(a)(b)(c)\3\2\1/     // A few simple numbered backreferences.
/(.)(a)(b)(c)\4\3\2/  // All need to be updated.

命名擷取功能是即將推出的功能,可讓開發人員為擷取畫面指派名稱,藉此減輕這些問題。語法類似 Perl、Java、.Net 和 Ruby:

const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
const result = pattern.exec('2017-07-10');
// result.groups.year === '2017'
// result.groups.month === '07'
// result.groups.day === '10'

命名擷取項目也可以透過命名回溯參照和 String.prototype.replace 參照:

// Named backreferences.
/(?<LowerCaseX>x)y\k<LowerCaseX>/.test('xyx');  // true

// String replacement.
const pattern = /(?<fst>a)(?<snd>b)/;
'ab'.replace(pattern, '$<snd>$<fst>');                              // 'ba'
'ab'.replace(pattern, (m, p1, p2, o, s, {fst, snd}) => fst + snd);  // 'ba'

如需這項新功能的完整詳細資料,請參閱規格提案

dotAll 標記

根據預設,規則運算式中的 . 原子會比對任何字元,但不包括行終止符:

/foo.bar/u.test('foo\nbar');   // false

這項提案引入了 dotAll 模式,可透過 /s 標記啟用。在 dotAll 模式中,. 也會比對行終止符。

/foo.bar/su.test('foo\nbar');  // true

如需這項新功能的完整詳細資料,請參閱規格提案

Unicode 屬性逃逸

在 ES2015 中導入 Unicode 感知功能後,系統突然出現許多可視為數字的字元,例如圈號 1:①;或視為字詞字元的字元,例如中文的「雪」字:雪。

這兩者都無法與 \d\w 配對。變更這些速記符號的含義會破壞現有的規則運算式模式。

而是推出新的屬性轉義序列。請注意,這些運算式僅適用於以 /u 標記的 Unicode 感知規則運算式。

/\p{Number}/u.test('①');      // true
/\p{Alphabetic}/u.test('雪');  // true

反向的對應項目可與 \P 配對。

/\P{Number}/u.test('①');      // false
/\P{Alphabetic}/u.test('雪');  // false

Unicode 聯盟定義了更多屬性,例如數學符號或日文平假字元:

/^\p{Math}+$/u.test('∛∞∉');                            // true
/^\p{Script_Extensions=Hiragana}+$/u.test('ひらがな');  // true

如需支援的 Unicode 屬性類別完整清單,請參閱目前的規格提案。如需更多範例,請參閱這篇實用文章

查看後方斷言

預覽斷言一開始就是 JavaScript 規則運算式語法的一部分。對應的後向斷言終於推出。有些人可能還記得,這項功能已在 V8 中實作一段時間了。我們甚至在幕後使用 lookbehind 斷言,實作 ES2015 中指定的 Unicode 標記。

名稱已清楚說明其意義。這可限制模式只在前方有 lookbehind 群組中的模式時才進行比對。它提供相符和不相符的版本:

/(?<=\$)\d+/.exec('$1 is worth about ¥123');  // ['1']
/(?<!\$)\d+/.exec('$1 is worth about ¥123');  // ['123']

如需更多詳細資訊,請參閱我們先前的網誌文章,該文章專門介紹 lookbehind 斷言,以及相關 V8 測試案例中的範例。

特別銘謝

這篇文章的內容若沒有提到為此付出辛勞的人員,就無法完整呈現。特別是語言專家 Mathias BynensDan EhrenbergClaude PacheBrian TerlsonThomas Wood、Gorkem Yakin,以及 Irregexp 專家 Erik Corry;此外,也要感謝所有為語言規格和 V8 實作這些功能做出貢獻的人員。

希望你也和我們一樣,對這些新的規則運算式功能感到興奮!