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 Bynens、Dan Ehrenberg、Claude Pache、Brian Terlson、Thomas Wood、Gorkem Yakin,以及 Irregexp 專家 Erik Corry;此外,也要感謝所有為語言規格和 V8 實作這些功能做出貢獻的人員。
希望你也和我們一樣,對這些新的規則運算式功能感到興奮!