Các tính năng biểu thức chính quy sắp ra mắt

Jakob Gruber
Dương Guo

ES2015 giới thiệu nhiều tính năng mới cho ngôn ngữ JavaScript, trong đó có những điểm cải tiến đáng kể đối với cú pháp biểu thức chính quy với cờ Unicode (/u) và cờ cố định (/y). Tuy nhiên, quá trình phát triển vẫn chưa dừng lại kể từ đó. Để cộng tác chặt chẽ với các thành viên khác tại TC39 (nội dung tiêu chuẩn ECMAScript), nhóm V8 đã đề xuất và đồng thiết kế một số tính năng mới để giúp biểu thức thông thường mạnh mẽ hơn nữa.

Những tính năng này hiện đang được đề xuất đưa vào quy cách JavaScript. Mặc dù các đề xuất chưa được chấp nhận hoàn toàn, nhưng các đề xuất đó đã ở Giai đoạn 3 trong quy trình TC39. Chúng tôi đã triển khai các tính năng này sau khi gắn cờ (xem bên dưới) để có thể kịp thời cung cấp ý kiến phản hồi về thiết kế và cách triển khai cho tác giả đề xuất tương ứng trước khi quy cách kỹ thuật hoàn tất.

Bài đăng này trên blog giúp bạn hé lộ sơ bộ về tương lai đầy thú vị này. Nếu bạn muốn làm theo các ví dụ sắp tới, hãy bật các tính năng JavaScript thử nghiệm tại chrome://flags/#enable-javascript-harmony.

Ảnh chụp được đặt tên

Biểu thức chính quy có thể chứa các hàm được gọi là chụp (hoặc nhóm), có thể thu thập một phần văn bản trùng khớp. Cho đến nay, nhà phát triển chỉ có thể tham chiếu đến các ảnh chụp này theo chỉ mục của họ, được xác định theo vị trí của ảnh chụp trong mẫu.

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'

Tuy nhiên, biểu thức chính quy vốn đã rất khó đọc, ghi và duy trì, đồng thời việc tham chiếu dạng số có thể làm tăng thêm nhiều chức năng. Ví dụ: trong các mẫu dài hơn, bạn có thể gặp khó khăn khi xác định chỉ mục của một ảnh chụp cụ thể:

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

Và thậm chí tệ hơn, những thay đổi đối với một mẫu có khả năng làm thay đổi chỉ mục của tất cả bản ghi hiện có:

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

Quy trình chụp ảnh có tên là một tính năng sắp ra mắt nhằm giúp giảm thiểu những vấn đề này bằng cách cho phép nhà phát triển chỉ định tên cho quy trình lưu giữ. Cú pháp tương tự như Perl, Java, .Net và 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'

Quy trình lưu giữ đã đặt tên cũng có thể được tham chiếu bằng tham chiếu ngược có tên và thông qua 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'

Bạn có thể xem toàn bộ thông tin chi tiết về tính năng mới này trong đề xuất quy cách.

cờ DotAll

Theo mặc định, nguyên tử . trong biểu thức chính quy khớp với mọi ký tự ngoại trừ dấu ngắt dòng:

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

Một đề xuất giới thiệu chế độ DotAll, được bật thông qua cờ /s. Ở chế độ DotAll, . cũng khớp với dấu ngắt dòng.

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

Bạn có thể xem toàn bộ thông tin chi tiết về tính năng mới này trong đề xuất quy cách.

Các ký tự thoát thuộc tính Unicode

Với nhận thức Unicode được giới thiệu trong ES2015, đột nhiên có thêm nhiều ký tự có thể được coi là số, ví dụ như chữ số một trong vòng tròn: 1; hoặc được coi là ký tự từ, ví dụ như ký tự tiếng Trung cho tuyết: 雪.

Không có yếu tố nào trong số này có thể kết hợp với \d hoặc \w. Việc thay đổi ý nghĩa của các cách viết tắt này sẽ phá vỡ các mẫu biểu thức chính quy hiện có.

Thay vào đó, chúng tôi sẽ ra mắt trình tự thoát thuộc tính mới. Lưu ý rằng chúng chỉ dùng được cho các biểu thức chính quy nhận biết Unicode được biểu thị bằng cờ /u.

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

Bạn có thể so khớp giá trị nghịch đảo bằng \P.

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

Hiệp hội Unicode xác định nhiều thuộc tính khác, ví dụ: ký hiệu toán học hoặc ký tự Hiragana tiếng Nhật:

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

Bạn có thể xem danh sách đầy đủ các lớp thuộc tính Unicode được hỗ trợ trong đề xuất quy cách hiện tại. Để biết thêm ví dụ, hãy xem bài viết chứa nhiều thông tin này.

Câu nhận định phía sau

Xác nhận có tính toán trước đã là một phần của cú pháp biểu thức chính quy của JavaScript ngay từ đầu. Phiên bản đối chiếu của họ, câu nhận định từ phía sau, cuối cùng cũng đã được giới thiệu. Một số bạn có thể nhớ rằng tính năng này đã có trên V8 từ khá lâu. Thậm chí, nâng cao, chúng tôi còn sử dụng các xác nhận tương ứng để triển khai cờ Unicode được chỉ định trong ES2015.

Tên này đã mô tả khá rõ ý nghĩa của nó. Lớp này cung cấp cách hạn chế một mẫu chỉ khớp nếu đứng sau mẫu trong nhóm giao diện. Có cả phiên bản phù hợp và không phù hợp:

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

Để biết thêm chi tiết, hãy xem bài đăng trên blog trước đây của chúng tôi dành riêng cho câu nhận định phía sau, và ví dụ trong các trường hợp kiểm thử V8 có liên quan.

Xác nhận

Bài đăng trên blog này sẽ không hoàn chỉnh nếu không đề cập đến một số người đã nỗ lực làm việc này: đặc biệt là những nhà vô địch ngôn ngữ Mathias Bynens, Dan Ehrenberg, Claude Pache, Brian Terlson, Thomas Wood, Gorkem Yakin và chuyên gia Irregexp Erik Corry và những người khác cũng đóng góp cho ngôn ngữ khác.

Chúng tôi hy vọng bạn quan tâm đến các tính năng biểu thức chính quy mới như chúng tôi!