FreeToGenerate.com

مجاني 100% · بدون تسجيل · لا شيء يغادر متصفحك

كل شيء يعمل داخل متصفحك — النمط والنص لا يُرسَلان إلى أي مكان.

متوفر أيضًا بلغات أخرى: English · Español · Português · Français

اختبار regex: جرّب التعابير النمطية مباشرة في متصفحك

أداة اختبار regex التي تعرض المطابقات ومجموعات الالتقاط والاستبدال فورًا، وتوقف أي نمط يقع في تراجع كارثي قبل أن يجمّد المتصفح.

ما هو اختبار regex؟

أداة اختبار regex هذه صفحة واحدة تتيح لك تجربة التعابير النمطية (regex) على نص حقيقي فورًا، بلا حاجة إلى فتح محرر أكواد أو تشغيل مفسّر لغة برمجة. تكتب النمط في حقل مخصص، وتلصق نص الاختبار في صندوق منفصل، فتظهر النتيجة أثناء الكتابة: عدد المطابقات، والزمن الذي استغرقه البحث بالمللي ثانية، ومكان كل مطابقة داخل النص مظلّلًا. الأداة تقبل نمطًا مجردًا مثل ^\d+$، وتقبل أيضًا الصياغة الكاملة كما تُكتب في JavaScript مثل /^\d+$/gi، فتقرأ الرايات (flags) الملصقة في آخر السلسلة تلقائيًا دون أن تضطر إلى فصلها يدويًا.

مع النمط ثمانية مفاتيح تمثل رايات JavaScript الثماني: g لعرض كل المطابقات لا أولها فقط، وi لتجاهل حالة الأحرف، وm لجعل ^ و$ يطابقان بداية كل سطر ونهايته لا بداية النص كله ونهايته، وs لجعل النقطة تطابق أسطر السطر الجديد، وu وv لتفعيل وضعي Unicode المختلفين، وy للمطابقة عند الموضع الحالي فقط دون تجاوزه، وd لتسجيل مواضع كل مجموعة التقاط. وإلى جانب عدّاد المطابقات وزمن البحث، تعرض الأداة جدولًا يفصّل كل مطابقة: موضعها في النص، والنص المطابق نفسه، ثم مجموعات الالتقاط المرقّمة، فالمجموعات المسمّاة إن وُجدت. وهناك حقل استبدال اختياري يفهم صيغ الاستبدال القياسية في JavaScript: $1 للمجموعة الأولى، و$<name> للمجموعة المسمّاة، و$& للنص المطابق كاملًا، فتعرض الأداة النص الناتج بعد الاستبدال فور كتابته.

وتحت هذا كله شريط صغير يخبرك بأي ميزات regex الحديثة يدعمها متصفحك أنت تحديدًا فعلًا، لا المواصفة النظرية: النظر الخلفي (lookbehind)، والمجموعات المسمّاة، وخصائص Unicode، والراية d، والراية v. هذا الاكتشاف يجري وقت التشغيل داخل متصفحك، فإن كان متصفحك قديمًا رأيت ميزة معطّلة بدل أن تحصل على خطأ غامض لا تعرف سببه.

كيفية الاستخدام

  1. الصق النمط في حقل النمط. اكتب نمطًا مجردًا مثل ^\d+$ أو الصق نصًا كاملًا مثل /^\d+$/gi فتُقرأ رايته تلقائيًا، ثم فعّل ما تحتاجه من المفاتيح الثمانية g وi وm وs وu وv وy وd.
  2. الصق نص الاختبار. ضع النص الذي تريد فحص النمط عليه في صندوق نص الاختبار، وستظهر كل مطابقة مظلّلة داخله فور الكتابة، إلى جانب عدّاد المطابقات وزمن البحث بالمللي ثانية.
  3. راجع الجدول وجرّب الاستبدال. افتح جدول المطابقات لترى موضع كل مطابقة ومجموعات الالتقاط المرقّمة والمسمّاة، واكتب في حقل الاستبدال الاختياري صيغة مثل $1 أو $<name> لترى النتيجة النهائية فورًا.

كيف يُسقط نمط رديء خادمًا كاملًا؟

بعض الأنماط تدخل فيما يُسمى التراجع الكارثي (catastrophic backtracking): حين يحمل النمط مُكمِّمًا متداخلًا داخل مُكمِّم آخر، مثل /^(a+)+$/، ويُطبَّق على نص لا يمكن أن يطابقه، يضطر محرك regex إلى تجربة كل تقسيم ممكن للنص بين المجموعتين قبل أن يستسلم. وقُيس هذا فعليًا على محرك JavaScript نفسه الذي يستعمله Chrome، بتطبيق هذا النمط على سلسلة من حرف a مكرر N مرة يتبعها علامة تعجب واحدة كي يستحيل النجاح: عند 22 حرفًا استغرق البحث 19 مللي ثانية، وعند 24 حرفًا 73 مللي ثانية، وعند 26 حرفًا 293 مللي ثانية، وعند 28 حرفًا 1170 مللي ثانية. كل حرف إضافي يضاعف العمل تقريبًا، وباستقراء هذه المضاعفة فإن سلسلة من نحو 38 حرفًا فقط ستحتاج قرابة عشرين دقيقة من البحث المتواصل — وهذا استقراء مبني على النمط الحسابي لا قياس فعلي عند هذا الطول.

وللمقارنة، قِيس النمط /^a+$/ الذي يؤدي العمل نفسه لكن بلا مُكمِّم متداخل: تطبيقه على 100000 حرف a استغرق 0.12 مللي ثانية فقط. فالفارق الهائل بين الحالتين لا علاقة له بحجم النص المُدخل، بل بشكل النمط نفسه؛ نص أقصر بآلاف المرات في الحالة الكارثية يستغرق وقتًا أطول بملايين المرات.

والمشكلة الحقيقية أن النمط الذي يقع في هذا التراجع لا ينتهي أبدًا من تلقاء نفسه، ولا شيء في الخيط (thread) الذي يعمل فيه يستطيع مقاطعته: لا مؤقّت، ولا فحص بين دورة وأخرى، لأن التحكم لا يعود إلى شفرتك أصلًا طوال مدة البحث. ولهذا تُشغَّل عمليات البحث في هذه الأداة داخل Web Worker منفصل عن الخيط الرئيسي، وأي نمط ما زال يعمل بعد ثانيتين يُوقَف قسرًا مع رسالة توضّح أن هذا هو التراجع الكارثي بعينه. هذا التصميم هو السبيل الوحيد لبقاء صفحة الأداة مستجيبة مهما كان النمط الذي تكتبه، وهو أيضًا ما يسمح للأداة أن تعرض لك الخطر بأمان: يمكنك أن تكتب نمطًا تعرف أنه سيُعلَّق، فتراقب كيف يُوقَف ويُبلَّغ عنه بدل أن يجمّد المتصفح كله.

وهذا الخطر ليس قدرًا محتومًا في كل محركات regex: محركا Go وRE2 لا يدعمان الإحالات الخلفية (backreferences) إطلاقًا، وهذا القيد بالذات هو ما يمنعهما من الوقوع في التراجع الكارثي من الأساس، لأن خوارزمياتهما تضمن زمنًا خطيًا مهما كان النمط. وهذه المقايضة بين قوة التعبير وضمان الأداء هي سبب رفض بعض الأنظمة — خصوصًا الخوادم التي تُشغّل أنماطًا يدخلها مستخدمون لا تثق بهم — لدعم هذه الميزة أصلًا.

حدود لا تُخفى

هذه الأداة تختبر نكهة (flavor) regex الخاصة بـJavaScript تحديدًا، لأنها تعمل داخل متصفحك بمحرك المتصفح نفسه، لا بمحرك عام يحاكي كل اللغات. ونكهة JavaScript تفتقر فعلًا إلى ميزات موجودة في نكهات أخرى: لا مجموعات ذرية (atomic groups)، ولا مُكمِّمات تملّكية (possessive quantifiers)، ولا استدعاء ذاتي (recursion)، ولا مرساتا \A و\z، ولا شروط (conditionals). فالنمط الذي تنسخه من إجابة تخص PCRE أو Python أو Perl قد لا يُصرَّف هنا أصلًا، وقد تحتاج إلى إعادة كتابته. لذلك فإن نتائج هذه الأداة قاطعة بالنسبة إلى JavaScript وحده، واسترشادية فقط إن كنت تكتب النمط للغة أخرى.

والنقطة نفسها ليست ثابتة المعنى: بلا الراية u تطابق وحدات UTF-16 لا نقاط ترميز Unicode، فرمز الإعجاب التعبيري الواحد يُحسب مطابقتين منفصلتين؛ ومع تفعيل u يُحسب مطابقة واحدة صحيحة. لكن حتى مع u، رمز مثل العائلة (رجل وامرأة وبنت وولد موصولين برابط غير ظاهر) هو سبع نقاط ترميز مختلفة ويبقى مع ذلك عنقودًا رسوميًا واحدًا (grapheme cluster) في نظر القارئ. فحتى الراية الأحدث لا تعطيك أحرفًا بالمعنى الذي يتبادر إلى الذهن، وهذا فرق يستحق الانتباه إذا كنت تعدّ طول نص فيه رموز تعبيرية مركّبة.

والنقطة الأهم للقارئ العربي أن \d في JavaScript محصور بأرقام ASCII وحدها: فهو لا يطابق الأرقام العربية المشرقية مثل ٣٤ إطلاقًا، بينما \p{Nd} مع الراية u يطابقها لأنه يعتمد على تصنيف Unicode للأرقام لا على مدى ثابت من الرموز. و\w يعاني العلة نفسها مع الحروف العربية: فهو لا يشملها البتة، فنمط مثل \w+ لن يلتقط كلمة عربية واحدة مهما طالت، والبديل الصحيح هو \p{L} مع الراية u، الذي يطابق أي حرف بحسب تصنيفه في Unicode لا بحسب موقعه في جدول ASCII.

وهناك فخّان يقع فيهما كثيرون: أولهما أن النمط الذي يحمل الراية g يحتفظ بخاصية lastIndex بين استدعاء وآخر لكائن التعبير نفسه، فاستدعاء .test() مرارًا على النص نفسه بالكائن نفسه يعيد true ثم false ثم true ثم false بالتناوب، لا نتيجة ثابتة كما قد يُتوقَّع. وثانيهما أن نمطًا قادرًا على مطابقة النص الفارغ مثل /a*/g يكسر حلقة البحث المعتادة: لا يتقدم الموضع عند مطابقة فارغة، فتدور الحلقة إلى الأبد ما لم يُقدَّم الموضع يدويًا، وبنقطة ترميز كاملة حين تكون الراية u مفعّلة، وإلا وقع التقديم بين نصفَي زوج بديل حيث لا يمكن أن تنجح أي مطابقة بعده. وإلى جانب هذين الفخّين، تفرض الأداة سقفين عمليّين: قائمة المطابقات المعروضة محدودة بألف مطابقة، وأي نمط ما زال يعمل بعد ثانيتين يُوقَف تلقائيًا مع رسالة توضّح ذلك.

لماذا هي مجانية؟

هذه الأداة مجانية لأن كل ما يجري فيها يحدث على جهازك أنت: النمط ونص الاختبار وعملية البحث نفسها لا تغادر متصفحك في أي لحظة، ولا تُرسَل إلى أي خادم لمعالجتها. فلا حاجة إلى إنشاء حساب، ولا علامة مائية على النتيجة، ولا رفع ملفات إلى أي مكان.

وهذا ينسحب على كل أدوات FreeToGenerate.com: كل أداة تعمل بالكامل داخل متصفحك، فتحصل على أداة كاملة الوظائف بلا قيد استخدام مخفي يظهر لاحقًا، وبلا شرط يجبرك على التسجيل لرؤية النتيجة الكاملة.