شرح مطابقة التعبيرات النمطية في JavaScript: كيفية استخدام match() وreplace() على النصوص
تُعدّ التعبيرات النمطية Regular Expressions أو اختصارًا Regex من أقوى الأدوات المتاحة للتعامل مع النصوص داخل JavaScript. ورغم أن كثيرًا من المطورين يدركون أهميتها، فإنها قد تبدو معقدة في البداية، خاصة لمن يخطون خطواتهم الأولى في البرمجة.
الخبر الجيد أن JavaScript توفر مجموعة من الدوال المدمجة التي تجعل استخدام Regex أكثر وضوحًا وسهولة، وأبرزها match() وmatchAll() وreplace() وreplaceAll(). في هذا الدليل ستتعرف على طريقة عمل هذه الدوال، ومتى تستخدم كل واحدة منها، وكيف توظفها بفعالية في معالجة النصوص واستخراج البيانات.
ما هي التعبيرات النمطية في JavaScript؟
التعبيرات النمطية هي أنماط بحث تُستخدم لمطابقة تسلسلات معينة داخل النصوص. وبدلًا من البحث اليدوي عن كلمة أو صيغة محددة، يمكنك بناء نمط ذكي يكتشف المطلوب تلقائيًا.
تدعم هذه الأنماط عناصر متعددة مثل:
- رموز خاصة مثل
*و+. - محددات وأنماط تحقق مثل
^و\W. - المجموعات والنطاقات مثل
(abc)و[123].
وعمليًا، يمكنك باستخدام Regex التحقق من تنسيق رقم هاتف، أو اكتشاف تكرار كلمة، أو استبدال جزء من نص طويل، أو استخراج بيانات محددة من محتوى غير منظم.
كيفية استخدام الدالة match() في JavaScript
إذا كانت التعبيرات النمطية مخصصة للبحث عن الأنماط داخل النصوص، فإن الدالة match() تُعد من أكثر الوسائل المباشرة للحصول على نتيجة المطابقة نفسها، وليس مجرد معرفة ما إذا كانت موجودة أم لا.
على عكس الدالة test() التي تُرجع قيمة منطقية true أو false فقط، فإن match() تُرجع المطابقة التي تم العثور عليها، أو تُرجع null إذا لم يوجد أي تطابق.
مثال أساسي على match()
const csLewisQuote = 'We are what we believe we are.';
const regex1 = /are/;
const regex2 = /eat/;
csLewisQuote.match(regex1);
// ["are", index: 3, input: "We are what we believe we are.", groups: undefined]
csLewisQuote.match(regex2);
// null
هذا السلوك مفيد جدًا عندما تحتاج إلى استخراج النتيجة المطابقة واستعمالها لاحقًا في المعالجة، من دون تعديل النص الأصلي.
ماذا تُرجع match()؟
- إذا وُجدت مطابقة، تُرجع مصفوفة
Arrayتحتوي على النتيجة. - إذا لم توجد مطابقة، تُرجع القيمة
null.
لكن هناك نقطة مهمة: عند استخدام match() من دون العلامة العامة g، فإنها تتوقف عند أول تطابق فقط.
أوضاع المطابقة المختلفة في match()
المطابقة الأولى فقط
const csLewisQuote = 'We are what we believe we are.';
const regex = /are/;
csLewisQuote.match(regex);
// ["are", index: 3, input: "We are what we believe we are.", groups: undefined]
في هذا الوضع، ستحصل على أول تطابق فقط، إلى جانب معلومات إضافية مثل موقعه داخل النص من خلال index، والنص الأصلي في input.
المطابقة الشاملة باستخدام g
إذا أردت العثور على جميع مرات ظهور النمط داخل النص، أضف العلامة العامة g إلى التعبير النمطي:
const csLewisQuote = 'We are what we believe we are.';
const regex = /are/g;
csLewisQuote.match(regex);
// ["are", "are"]
هنا ستحصل على جميع التطابقات، لكن من دون المعلومات الإضافية مثل index الخاصة بكل نتيجة.
حساسية الأحرف الكبيرة والصغيرة
من المهم أن تتذكر أن التعبيرات النمطية في JavaScript حساسة لحالة الأحرف Case Sensitive بشكل افتراضي.
لنأخذ المثال التالي:
const csLewisQuote = 'We are what we believe we are.';
const regex = /we/g;
csLewisQuote.match(regex);
// ["we", "we"]
في هذا المثال، النمط /we/g يطابق فقط الكلمة المكتوبة بحرف w صغير، لذلك لم يلتقط We الموجودة في بداية الجملة.
الحل الأول: تحويل النص باستخدام toLowerCase()
const csLewisQuote = 'We are what we believe we are.'.toLowerCase();
const regex = /we/g;
csLewisQuote.match(regex);
// ["we", "we", "we"]
هذه الطريقة مناسبة عندما لا يهمك الاحتفاظ بالشكل الأصلي للنص.
الحل الثاني: استخدام العلامة i
const csLewisQuote = 'We are what we believe we are.';
const regex = /we/gi;
csLewisQuote.match(regex);
// ["We", "we", "we"]
العلامة i تجعل البحث غير حساس لحالة الأحرف، بينما تحافظ على النص الأصلي كما هو.
متى تستخدم matchAll() بدلًا من match()؟
أُضيفت الدالة matchAll() إلى JavaScript لتقديم أسلوب أكثر مرونة عند الحاجة إلى جميع التطابقات مع تفاصيلها الكاملة.
على عكس match()، فإن matchAll():
- تتطلب استخدام العلامة العامة
g. - تُرجع كائنًا قابلًا للتكرار
Iteratorبدلًا من مصفوفة مباشرة. - تُعدّ أكثر فائدة عند العمل مع مجموعات الالتقاط
Capture Groups.
مثال على matchAll()
const csLewisQuote = 'We are what we believe we are.';
const regex1 = /we/gi;
const regex2 = /eat/gi;
[...csLewisQuote.matchAll(regex1)];
// [
// ["We", index: 0, input: "We are what we believe we are.", groups: undefined],
// ["we", index: 12, input: "We are what we believe we are.", groups: undefined],
// ["we", index: 23, input: "We are what we believe we are.", groups: undefined]
// ]
[...csLewisQuote.matchAll(regex2)];
// []
الميزة الأهم هنا أنك تحصل على كل التطابقات مع موقع كل منها داخل النص، بدل الاكتفاء بقائمة قيم مختصرة فقط.
فائدة matchAll() مع مجموعات الالتقاط
const csLewisRepeat = "We We are are";
const repeatRegex = /(\w+)\s\1/g;
csLewisRepeat.match(repeatRegex);
// ["We We", "are are"]
const csLewisRepeat = "We We are are";
const repeatRegex = /(\w+)\s\1/g;
[...csLewisRepeat.matchAll(repeatRegex)];
// [
// ["We We", "We", index: 0, input: "We We are are", groups: undefined],
// ["are are", "are", index: 6, input: "We We are are", groups: undefined]
// ]
يتضح هنا أن matchAll() لا تكتفي بإرجاع النص الكامل المطابق، بل تمنحك أيضًا القيم الملتقطة داخل الأقواس، وهذا يجعلها مناسبة جدًا في مهام التحليل المتقدم للنصوص.
كيفية استخدام replace() لاستبدال النصوص
بعد العثور على الأنماط داخل السلاسل النصية، تأتي الخطوة التالية غالبًا وهي استبدالها بقيم جديدة. وهنا تظهر قوة الدالة replace().
تستقبل replace() وسيطين:
- النص أو التعبير النمطي المراد مطابقته.
- النص البديل الذي سيحل محل النمط المطابق.
مثال عملي على replace()
const campString = 'paidCodeCamp';
const fCCString1 = campString.replace('paid', 'free');
const fCCString2 = campString.replace(/paid/, 'free');
console.log(campString);
// "paidCodeCamp"
console.log(fCCString1);
// "freeCodeCamp"
console.log(fCCString2);
// "freeCodeCamp"
الميزة المهمة هنا أن replace() لا تُعدّل النص الأصلي، بل تُرجع سلسلة نصية جديدة فقط.
استبدال أول تطابق فقط
مثل match()، تقوم replace() افتراضيًا باستبدال أول تطابق فقط إذا لم تستخدم العلامة g.
const campString = 'paidCodeCamp is awesome. You should check out paidCodeCamp.';
const fCCString1 = campString.replace('paid', 'free');
const fCCString2 = campString.replace(/paid/g, 'free');
console.log(fCCString1);
// "freeCodeCamp is awesome. You should check out paidCodeCamp."
console.log(fCCString2);
// "freeCodeCamp is awesome. You should check out freeCodeCamp."
مراعاة حساسية الأحرف عند الاستبدال
const campString = 'PaidCodeCamp is awesome. You should check out PaidCodeCamp.';
const fCCString1 = campString.replace('Paid', 'free');
const fCCString2 = campString.replace(/paid/gi, 'free');
console.log(fCCString1);
// "freeCodeCamp is awesome. You should check out PaidCodeCamp."
console.log(fCCString2);
// "freeCodeCamp is awesome. You should check out freeCodeCamp."
إذا كنت تتعامل مع نصوص قد تتغير فيها حالة الأحرف، فمن الأفضل غالبًا استخدام العلامة i مع التعبير النمطي لضمان نتائج أدق.
ما الفرق بين replace() وreplaceAll()؟
تأتي الدالة replaceAll() كامتداد أكثر وضوحًا للدالة replace() عندما يكون الهدف هو استبدال جميع التطابقات دفعة واحدة.
const campString = 'paidCodeCamp is awesome. You should check out paidCodeCamp.';
const fCCString1 = campString.replaceAll('paid', 'free');
const fCCString2 = campString.replaceAll(/paid/g, 'free');
console.log(fCCString1);
// "freeCodeCamp is awesome. You should check out freeCodeCamp."
console.log(fCCString2);
// "freeCodeCamp is awesome. You should check out freeCodeCamp."
الفرق الأساسي هو أن replaceAll() أكثر تعبيرًا من ناحية القراءة، كما أنها تستبدل جميع التطابقات مباشرة عند تمرير نص عادي كوسيط أول. أما إذا استخدمت تعبيرًا نمطيًا معها، فيجب أن يتضمن العلامة g.
متى تختار كل دالة؟
| الدالة | أفضل استخدام | النتيجة |
|---|---|---|
test() |
التحقق السريع من وجود نمط | true أو false |
match() |
الحصول على أول تطابق أو جميع القيم المختصرة | Array أو null |
matchAll() |
الحصول على جميع التطابقات مع التفاصيل ومجموعات الالتقاط | Iterator |
replace() |
استبدال أول تطابق أو استبدال مخصص باستخدام Regex |
سلسلة نصية جديدة |
replaceAll() |
استبدال جميع التطابقات بوضوح أكبر | سلسلة نصية جديدة |
نصائح عملية لاستخدام Regex بكفاءة
- استخدم
test()عندما يكون المطلوب مجرد التحقق من وجود نمط لتوفير الأداء. - استخدم
matchAll()إذا كنت بحاجة إلى كل التطابقات مع مواقعها ومجموعات الالتقاط. - أضف العلامتين
gوiبحذر حسب الحاجة، لأنهما تغيّران سلوك البحث جذريًا. - اختبر التعبير النمطي على أمثلة متعددة قبل اعتماده في مشروع إنتاجي.
- حافظ على بساطة الأنماط قدر الإمكان، لأن التعابير المعقدة تصبح صعبة الصيانة لاحقًا.
الخلاصة التقنية
فهم الدوال match() وmatchAll() وreplace() وreplaceAll() يمنحك أساسًا قويًا للتعامل الاحترافي مع النصوص في JavaScript. من الناحية التقنية، لا تكمن القوة الحقيقية في حفظ الأنماط المعقدة، بل في معرفة الأداة الأنسب لكل حالة استخدام. عندما تجمع بين تعبير نمطي واضح ودالة مناسبة، ستتمكن من بناء حلول دقيقة وسريعة وقابلة للتوسع في تطبيقات الويب الحديثة.