الميزات القادمة للتعبير العادي

جاكوب غروبر
يانغ غو

قدّم ES2015 العديد من الميزات الجديدة للغة JavaScript، بما في ذلك تحسينات مهمة على بنية التعبير العادي باستخدام علامات Unicode (/u) والعلامات الثابتة (/y). إلا أن التطوير لم يتوقف منذ ذلك الحين. في إطار التعاون الوثيق مع أعضاء آخرين في TC39 (هيئة معايير ECMAScript)، اقترح فريق V8 العديد من الميزات الجديدة وشارك في تصميمها لجعل التعبيرات العادية أكثر فعالية.

يتم اقتراح هذه الميزات حاليًا لتضمينها في مواصفات JavaScript. وعلى الرغم من عدم قبول الاقتراحات بالكامل، إلا أنّها ما زالت في المرحلة الثالثة من عملية TC39. لقد طبّقنا هذه الميزات بناءً على علامة (انظر أدناه) لنتمكن من تقديم ملاحظات وآراء حول التصميم والتنفيذ في الوقت المناسب إلى مؤلفي الاقتراحات المعنيين قبل الانتهاء من تحديد المواصفات.

تمنحك مشاركة المدونة هذه معاينة لهذا المستقبل المثير. إذا كنت تريد المتابعة مع الأمثلة القادمة، يمكنك تفعيل ميزات JavaScript التجريبية على chrome://flags/#enable-javascript-harmony.

اللقطات المُسَمّاة

يمكن أن تحتوي التعبيرات العادية على ما يُعرف باسم عمليات الالتقاط (أو المجموعات)، والتي يمكنها التقاط جزء من النص المتطابق. وحتى الآن، لا يمكن للمطوّرين سوى الإشارة إلى هذه اللقطات من خلال الفهرس الخاص بهم، والذي يتم تحديده من خلال موضع التقاط الصور ضمن النمط.

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'

تتوفّر التفاصيل الكاملة لهذه الميزة الجديدة في اقتراح المواصفات.

علامة نقطة الكل

وفقًا للإعدادات التلقائية، تتطابق ذرة . في التعبيرات العادية مع أي حرف باستثناء نهايات الأسطر:

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

يقدِّم الاقتراح وضع dotAll الذي يتم تفعيله من خلال علامة /s. في dotAllmode، يتطابق . مع نهاية الأسطر أيضًا.

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

تتوفّر التفاصيل الكاملة لهذه الميزة الجديدة في اقتراح المواصفات.

أحرف الإلغاء في سمة يونيكود

مع إطلاق التوعية بيونيكود في ES2015، ازداد عدد

لا يمكن مطابقة أيٍّ من هذين الخيارين مع \d أو \w. سيؤدي تغيير معنى هذه الاختصارات إلى كسر أنماط التعبير العادي الحالية.

وبدلاً من ذلك، يتمّ إطلاق تسلسلات جديدة لإلغاء الموقع الإلكتروني. تجدر الإشارة إلى أنّها لا تتوفّر إلا للتعبيرات العادية المستندة إلى يونيكود والتي يُشار إليها بالعلامة /u.

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

ويمكن مطابقة المعكوس باستخدام \P.

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

يحدد اتحاد يونيكود العديد من الخصائص الأخرى، على سبيل المثال لرموز الرياضيات أو أحرف الهيراغانا اليابانية:

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

ويمكن العثور على القائمة الكاملة لفئات سمات يونيكود المتاحة في اقتراح المواصفات الحالي. للاطّلاع على المزيد من الأمثلة، يمكنك قراءة هذه المقالة المفيدة.

تأكيدات من وراء الكواليس

كانت تأكيدات النظرة الأمامية جزءًا من بنية التعبيرات العادية في JavaScript منذ البداية. ويتم الآن تقديم التأكيدات النظيرة لنظيراتها. قد يتذكر بعضكم أن هذا كان جزءًا من V8 منذ فترة طويلة بالفعل. كما نستخدم أيضًا تأكيدات من وراء الكواليس لتنفيذ علامة يونيكود المحددة في ES2015.

يصف الاسم بالفعل معناه بشكل جيد. وهو يوفر طريقة لتقييد نمط ما لمطابقته فقط إذا كان مسبوقًا بالنمط الموجود في مجموعة المظهر الخلفي. إنه يأتي في كل من النكهات المطابقة وغير المطابقة:

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

للاطّلاع على مزيد من التفاصيل، يمكنك الاطّلاع على مشاركة المدوّنة السابقة الخاصة بنا والمخصصة للتحقق من صحة التأكيدات، والأمثلة حول حالات الاختبار V8 ذات الصلة.

شكر وتقدير

لن تكتمل مشاركة المدونة هذه بدون ذكر بعض الأشخاص الذين عملوا بجد لتحقيق ذلك: لا سيما أبطال اللغات ماثياس بينينز ودان إرينبيرغ وكلود باش وبراين تيرلسون وتوماس وود وغوركيم ياكين وإيركيم جورو إريك كوري إريك كوري والتي ساهموا أيضًا في تنفيذ هذه

نأمل أن تكونوا متحمسين بشأن ميزات التعبير العادي الجديدة هذه بقدر حماسنا.