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

Jkob Gruber
Yang Guo

ES2015 在 JavaScript 語言推出了許多新功能,包括對使用萬國碼 (Unicode) (/u) 和固定式 (/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 標記

根據預設,規則運算式中的 . Atom 會比對任何字元,但行結束字元除外:

/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 的一部分。我們甚至會運用 Look 斷言,實作 ES2015 中指定的 Unicode 標記。

名稱已經能充分描述它的意義。這個方法可將模式限制為僅在前方有模式時進行比對。有相符和不相符的變種版本:

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

詳情請參閱我們的上一篇網誌文章,其中專門發表斷言,以及相關 V8 測試案例的範例。

特別銘謝

這篇網誌文章之所以如此,是因為有部分已努力達成這個目標的人,便是如此。尤其是語言冠軍 Mathias BynensDan EhrenbergClaude PacheBrian TerlsonThomas Wood、Gorkem Yakin 和 Irregexp guru 也貢獻了這些語言,其他員工也有所貢獻。

希望您和我們一樣,對新的規則運算式功能感到滿意!