كتابة تعابير نمطية (RegEx) متقدمة في جافاسكربت
تعتبر التعبيرات النمطية أو الـ Regular Expressions (RegEx) من الأدوات القوية جداً في البرمجة، وخصوصاً في جافاسكربت، فهي تتيح للمبرمجين إمكانية البحث، المطابقة، والاستبدال النصي بطرق متقدمة وفعالة. ورغم أن التعبيرات النمطية قد تبدو معقدة في البداية، فإن إتقانها يفتح آفاقاً واسعة لتحليل النصوص، التحقق من صحة البيانات، وتنفيذ عمليات بحث واستبدال معقدة جداً ضمن السلاسل النصية.
في هذا المقال، سنتناول تعابير نمطية متقدمة في جافاسكربت، مع التركيز على بناءها وفهم تركيبها، بالإضافة إلى استعراض تقنيات وممارسات متقدمة لتعزيز قدرات RegEx عند استخدامها في المشاريع البرمجية.
مقدمة عن التعبيرات النمطية في جافاسكربت
التعبيرات النمطية هي نماذج تستخدم لوصف مجموعات من النصوص. تسمح بالتحقق من تطابق نص معين مع نمط معين، أو استخراج أجزاء من النص، أو استبدالها بأنماط أخرى. في جافاسكربت، يمكن إنشاء تعابير نمطية بطريقتين:
-
باستخدام القوسين المائلين
/.../، وهي الطريقة الشائعة. -
باستخدام الكائن
RegExpالذي يوفر مرونة أكبر مثل إنشاء نماذج بناءً على متغيرات ديناميكية.
مثال بسيط لتعريف تعبير نمطي:
jsconst regex = /hello/;
يقوم هذا التعبير بالبحث عن النص “hello” في النصوص المعطاة.
لكن في الاستخدامات المتقدمة، تتطلب التعبيرات النمطية بناء أنماط أكثر تعقيدًا تشمل تكرار أجزاء، مجموعات، شروط، واستدعاءات ضمنية وغيرها.
مكونات التعبير النمطي الأساسية والمتقدمة
1. الرموز الأساسية (Literals)
هي الأحرف التي تبحث عنها مباشرة، مثل:
js/abc/ // تبحث عن الحروف "abc" المتتابعة في النص
2. رموز التحكم (Metacharacters)
تمثل أوامر خاصة داخل التعبير النمطي تؤثر على سلوك البحث، مثل:
-
.تعبر عن أي حرف عدا نهاية السطر. -
^بداية السلسلة النصية. -
$نهاية السلسلة النصية. -
\dرقم (0-9). -
\wحرف أو رقم أو الشرطة السفلية (underscore). -
\sفراغ أو مسافة. -
\bحدود الكلمة.
3. المجموعات (Groups) والتجمّعات (Character Classes)
-
المجموعة: تجمع مجموعة من الأحرف معاً ضمن أقواس مربعة
[]للبحث عن أي منها.
مثال:
js/[abc]/ // يبحث عن الحرف a أو b أو c
-
النطاق داخل المجموعة:
js/[a-z]/ // يبحث عن أي حرف صغير من a إلى z
-
النفي داخل المجموعة:
js/[^0-9]/ // يبحث عن أي حرف غير رقم
-
المجموعة التقسيمية (Capturing groups):
js/(abc)/ // تجميع abc كوحدة يمكن استدعاؤها لاحقاً أو الرجوع إليها
أنماط متكررة (Quantifiers)
تسمح بالتحكم في عدد تكرار العناصر أو المجموعات، وهي تشمل:
-
*تكرار صفر أو أكثر -
+تكرار واحد أو أكثر -
?تكرار صفر أو واحد (اختياري) -
{n}التكرار بالضبط n مرة -
{n,}التكرار n مرة أو أكثر -
{n,m}التكرار بين n و m مرات
مثال:
js/\d{3}/ // يبحث عن 3 أرقام متتالية
تقنيات متقدمة في التعبيرات النمطية
1. استخدام المجموعات التقسيمية (Capturing Groups) والرجوع إليها (Backreferences)
المجموعات التقسيمية تسمح بتجميع جزء من التعبير النمطي ليتم التعامل معه كوحدة واحدة أو للاستخدام لاحقاً. يمكن الرجوع إلى هذه المجموعات عبر الرموز \1, \2, …، حسب ترتيب المجموعة.
مثال:
jsconst regex = /(\w+)\s\1/;
const str = "hello hello";
console.log(regex.test(str)); // true
في هذا المثال، التعبير يبحث عن كلمة متبوعة بمسافة ثم نفس الكلمة مرة أخرى. استخدام \1 يشير إلى الجزء الذي التقطته المجموعة الأولى.
2. المجموعات غير التقسيمية (Non-capturing groups)
في بعض الأحيان نحتاج لتجميع عناصر معًا دون الحاجة إلى الرجوع إليها لاحقًا، وهنا تُستخدم الأقواس مع ?::
js/(?:abc)+/ // يكرر سلسلة "abc" واحدة أو أكثر بدون التقاط للمجموعة
هذا يقلل من استهلاك الموارد عند عدم الحاجة إلى استخدام المجموعة لاحقًا.
3. التعبيرات الشرطية (Lookahead & Lookbehind)
a) التحقق الأمامي (Lookahead)
يسمح بالتأكد من وجود نمط معين بعد النص الحالي، دون تضمينه في الناتج.
-
التحقق الإيجابي الأمامي
(?=...)
مثال:
js/\w+(?=\d)/ // يبحث عن كلمة تليها رقم مباشرة، الرقم غير مشمول في المطابقة
-
التحقق السلبي الأمامي
(?!...)
مثال:
js/\w+(?!\d)/ // كلمة لا تليها رقم
b) التحقق الخلفي (Lookbehind)
يعمل بالعكس، يتحقق مما يوجد قبل النص الحالي.
-
التحقق الإيجابي الخلفي
(?<=...) -
التحقق السلبي الخلفي
(?
مثال:
js/(?<=\$)\d+/ // أرقام تسبقها علامة الدولار $
4. التطابق مع الأنماط المتعددة (Alternation)
يستخدم الرمز | للفصل بين أنماط متعددة للتطابق مع أي منها:
js/cat|dog|bird/ // يبحث عن أي من الكلمات cat أو dog أو bird
5. التعامل مع الرموز الخاصة والتهرب (Escaping)
بعض الأحرف تحمل معاني خاصة داخل التعبير النمطي مثل .، *، +، ?، (، )، [، ]، \، $، ^، {، }، |. للتعامل معها كأحرف عادية، يجب هروبها بواسطة \.
بناء تعبير نمطي متقدم في جافاسكربت: أمثلة واقعية
المثال الأول: التحقق من صحة البريد الإلكتروني
التحقق من صحة البريد الإلكتروني يعد من أشهر استخدامات التعبيرات النمطية، ويمكن تصميم تعبير نمطي متقدم يغطي أغلب حالات البريد الإلكتروني المقبولة.
jsconst emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
-
يبدأ التعبير بـ
^و ينتهي بـ$لضمان المطابقة الكاملة للنص. -
الجزء الأول
[a-zA-Z0-9._%+-]+يغطي اسم المستخدم مع الحروف والأرقام وبعض الرموز الخاصة. -
الجزء بعد
@يتحقق من النطاق domain. -
\.[a-zA-Z]{2,}يتحقق من امتداد النطاق مثل com أو org.
المثال الثاني: استخراج تواريخ بتنسيق محدد (YYYY-MM-DD)
jsconst dateRegex = /(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])/;
-
\d{4}السنة مكونة من 4 أرقام. -
(0[1-9]|1[0-2])تحقق من الشهر بين 01 و 12. -
(0[1-9]|[12]\d|3[01])تحقق من اليوم بين 01 و 31.
المثال الثالث: البحث عن تكرار كلمة معينة في نص
jsconst repeatWordRegex = /\b(\w+)\b\s+\1\b/gi;
-
\bيحدد حدود الكلمات. -
(\w+)يلتقط كلمة. -
\s+مسافات بين الكلمات. -
\1الرجوع إلى الكلمة السابقة (تكرارها).
المثال الرابع: التحقق من أرقام الهواتف
مثال متقدم للتحقق من أرقام هواتف دولية بتنسيقات مختلفة:
jsconst phoneRegex = /^\+?(\d{1,3})?[-.\s]?(\(?\d{1,4}\)?)[-.\s]?(\d{1,4})[-.\s]?(\d{1,9})$/;
-
^\+?بداية رقم هاتف قد يحتوي على علامة +. -
(\d{1,3})?كود الدولة (اختياري). -
[-.\s]?فاصل مثل الشرطة أو النقطة أو مسافة. -
(\(?\d{1,4}\)?)كود المنطقة مع احتمال وجود أقواس. -
(\d{1,4})رقم محلي أول. -
(\d{1,9})باقي الرقم.
تحسين أداء التعبيرات النمطية
1. تجنب المطابقات الجشعة (Greedy Matching)
بشكل افتراضي، الكميات مثل * و + هي جشعة، تعني أنها تحاول مطابقة أكبر عدد ممكن من الأحرف، مما قد يؤدي إلى نتائج غير مرغوبة وأداء أبطأ.
لجعلها غير جشعة، نضيف ? بعد الكمية:
js/.*?/ // تطابق أقل عدد ممكن من الأحرف
2. استخدام المجموعات غير التقسيمية لتحسين الأداء
عندما لا تكون هناك حاجة لاستخدام المجموعات التقسيمية (Capturing Groups)، يفضل استخدام المجموعات غير التقسيمية (?:...) لتقليل العمليات الحسابية داخل المحرك.
3. التحقق من أن التعبير النمطي ليس معقدًا بشكل مفرط
كلما زادت التعقيدات داخل التعبير، كلما زاد استهلاك الموارد، وقد يؤدي ذلك إلى بطء أو حتى انهيار التطبيق إذا تم استخدام تعبير نمطي غير محسوب جيدًا مع نصوص كبيرة.
أدوات مساعدة لتصميم واختبار التعبيرات النمطية
يستخدم المطورون العديد من الأدوات التي تسهل عملية كتابة واختبار التعبيرات النمطية، منها:
-
Regex101: موقع تفاعلي يتيح كتابة التعبيرات النمطية مع شرح لكل جزء في التعبير، ودعم عدة لغات برمجة من ضمنها جافاسكربت.
-
RegExr: أداة تفاعلية أخرى تسمح بكتابة واختبار التعبيرات النمطية مباشرة.
-
Chrome DevTools: أداة مطور جافاسكربت في المتصفح تدعم اختبار التعبيرات النمطية ضمن وحدة التحكم.
استخدامات متقدمة أخرى
1. استبدال النصوص مع الدوال
في جافاسكربت، يمكن استخدام التعبيرات النمطية مع دالة replace التي تقبل دالة كوسيط ثاني لتنفيذ استبدالات مخصصة بناءً على نتائج المطابقة.
jsconst text = "The price is $100";
const result = text.replace(/\$(\d+)/, (match, p1) => {
return `USD ${p1}`;
});
console.log(result); // "The price is USD 100"
2. تقسيم النص (Split) باستخدام تعبير نمطي
يمكن استخدام split مع التعبيرات النمطية لفصل نص بناءً على أنماط معقدة بدلاً من حرف ثابت.
jsconst data = "apple, orange; banana|grape";
const fruits = data.split(/[,;|]\s*/);
console.log(fruits); // ["apple", "orange", "banana", "grape"]
3. البحث عن نصوص متعددة الخطوط
استخدام علامة m في نهاية التعبير لتمكين نمط متعدد الأسطر، بحيث يؤثر ^ و $ على بداية ونهاية كل سطر بدلاً من النص الكامل فقط.
jsconst multilineText = `first line
second line
third line`;
const regex = /^second/m;
console.log(regex.test(multilineText)); // true
الجدول التالي يلخص أهم رموز وتعابير RegEx المتقدمة في جافاسكربت
| الرمز أو التعبير | الوصف | المثال |
|---|---|---|
. |
أي حرف عدا نهاية السطر | /a.c/ تطابق "abc" و "a3c" |
\d |
رقم من 0 إلى 9 | /\d+/ تطابق سلسلة من الأرقام |
\w |
حرف أو رقم أو الشرطة السفلية | /\w+/ تطابق كلمة |
\s |
مسافة أو فراغ | /\s+/ تطابق مسافات متتالية |
^ |
بداية النص (أو السطر مع m flag) |
/^Hello/ تطابق بداية النص بـ "Hello" |
$ |
نهاية النص (أو السطر مع m flag) |
/world$/ تطابق نهاية النص بـ "world" |
* |
صفر أو أكثر من التكرار (جشع) | /a*/ تطابق "aaaa" أو "" |
+ |
واحد أو أكثر من التكرار (جشع) | /a+/ تطابق "a" أو "aaaa" |
? |
صفر أو مرة واحدة (اختياري) | /a?b/ تطابق "b" أو "ab" |
{n,m} |
بين n و m تكرار | /a{2,4}/ تطابق "aa" إلى "aaaa" |
(abc) |
مجموعة تقسيمية | /(\d{3})/ تقسم 3 أرقام |
(?:abc) |
مجموعة غير تقسيمية | /(?:abc)+/ تكرار "abc" بدون التقاط |
\1, \2 |
الرجوع للمجموعات التقسيمية | /(\w+)\s\1/ تطابق كلمة متكررة |
(?=...) |
التحقق الإيجابي الأمامي | /\w+(?=\d)/ كلمة تليها رقم |
(?!...) |
التحقق السلبي الأمامي | /\w+(?!\d)/ كلمة لا تليها رقم |
(?<=...) |
التحقق الإيجابي الخلفي | /(?<=\$)\d+/ رقم بعد $ |
(? |
التحقق السلبي الخلفي | /\d+(? رقم ليس بعد $ |
| ` | ` | أو (Alternation) |
g |
العلم العالمي (Global) | /abc/g تطابق جميع الحالات |
i |
تجاهل حالة الأحرف (Case-insensitive) | /abc/i تطابق "ABC" و "abc" |
m |
نمط متعدد الأسطر (Multi-line) | /^abc/m تطابق "abc" بداية أي سطر |
خلاصة
التعبيرات النمطية في جافاسكربت تمثل أداة لا غنى عنها في معالجة النصوص، ويمكن تطويرها لتصبح قوية جداً عند استخدام تقنيات متقدمة مثل المجموعات التقسيمية، التحقق الشرطي، الرجوع إلى المجموعات، وغيرها من الميزات التي تجعلها قابلة للتكيف مع سيناريوهات معقدة ومتعددة.
إتقان هذه التعابير يتطلب ممارسة مستمرة وفهمًا عميقًا لتركيبها وأداءها، إلى جانب القدرة على تصميم أنماط تحقق بدقة وتناسب الاحتياجات البرمجية المختلفة. كما أن هناك العديد من الأدوات التي تسهل عملية الاختبار والتطوير، ما يجعلها أكثر فعالية وأماناً في الاستخدام.
يجب دائمًا التفكير في تحسين الأداء عند كتابة تعبير نمطي معقد، وذلك لتفادي التأثير على سرعة التطبيق، لا سيما في حالات التعامل مع نصوص كبيرة أو في بيئات إنتاج حقيقية.
المصادر والمراجع
-
MDN Web Docs: Regular Expressions - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
-
Regular-Expressions.info: Advanced Regular Expressions - https://www.regular-expressions.info/advanced.html

