الكائنات والتعبيرات العادية مختلفة. دليل للتعبيرات العادية في جافا سكريبت. التحقق من وجود مباريات

التعبيرات العاديةتتيح لك إجراء بحث مرن عن الكلمات والتعابير في النصوص بهدف حذفها أو استخراجها أو استبدالها.

بناء الجملة:

// الخيار الأول لإنشاء تعبير عادي var regexp=new RegExp( عينة,الصفات التعريفية); // الخيار الثاني لإنشاء تعبير عادي var regexp=/ عينة/الصفات التعريفية;

عينةيسمح لك بتحديد نمط الأحرف للبحث.

الصفات التعريفيةتسمح لك بتخصيص سلوك البحث:

  • أنا- البحث دون مراعاة حالة الحروف؛
  • ز- البحث الشامل (سيتم العثور على جميع التطابقات في الوثيقة، وليس فقط الأولى)؛
  • م- بحث متعدد الخطوط.

البحث عن الكلمات والتعبيرات

أبسط استخدام للتعبيرات العادية هو البحث عن الكلمات والتعبيرات في النصوص المختلفة.

فيما يلي مثال لاستخدام البحث باستخدام المعدلات:

// تعيين التعبير العادي rv1 rv1=/روسيا/; // حدد التعبير العادي rv2 rv2=/russia/g; // حدد التعبير العادي rv3 rv3=/russia/ig; // غامق يشير إلى مكان العثور على التطابقات في النص عند استخدام // التعبير rv1: روسيا هي أكبر دولة في العالم. حدود روسيا مع 18 دولة. روسيا هي دولة خليفة للاتحاد السوفييتي. // غامق يشير إلى مكان العثور على التطابقات في النص عند استخدام // التعبير rv2: روسيا هي أكبر دولة في العالم. حدود روسيا مع 18 دولة. روسيا هي دولة خليفة لاتحاد الجمهوريات الاشتراكية السوفياتية."; // الخط الغامق يشير إلى مكان العثور على المطابقات في النص عند استخدام // التعبير rv3: روسيا هي أكبر دولة في العالم. حدود روسيا هي 18 دولة. الدولة الوريثة لاتحاد الجمهوريات الاشتراكية السوفياتية.";

رموز خاصة

بالإضافة إلى الأحرف العادية، يمكن استخدام أنماط التعبير العادي رموز خاصة(الأحرف الأولية). يتم عرض الأحرف الخاصة مع الأوصاف في الجدول أدناه:

حرف خاص وصف
. يطابق أي حرف باستثناء حرف نهاية السطر.
يطابق أي حرف أبجدي.
يطابق أي حرف غير أبجدي.
يطابق الأحرف التي هي أرقام.
يطابق الأحرف التي ليست أرقامًا.
يطابق أحرف المسافة البيضاء.
يطابق الأحرف التي لا تحتوي على مسافات بيضاء.
سيتم العثور على التطابقات فقط عند حدود الكلمات (البداية أو النهاية).
سيتم البحث عن التطابقات فقط على حدود غير الكلمات.
يطابق حرف السطر الجديد.

/* سيجد تعبير reg1 جميع الكلمات التي تبدأ بحرفين عشوائيين وتنتهي بـ "vet". بما أن الكلمات في الجملة مفصولة بمسافة، فسنضيف حرفًا خاصًا \s في البداية وفي النهاية */ reg1=/\s..vet\s/g; txt="مرحبًا بخزانة سروال قصير العهد"; document.write(txt.match(reg1) + "
"); /* سيجد تعبير reg2 جميع الكلمات التي تبدأ بثلاثة أحرف عشوائية وتنتهي بـ "vet" */ reg2=/\s...vet\s/g; document.write(txt.match(reg2) + "
"); txt1=" hi2hello hi 1hello "; /* سيبحث تعبير reg3 عن جميع الكلمات التي تبدأ بـ "at" متبوعة برقم واحد وتنتهي بـ "vet" */ var reg3=/at\dvet/g; document . الكتابة (txt1.match(reg3) + "
"); // سيجد التعبير reg4 جميع الأرقام الموجودة في النص var reg4=/\d/g; txt2="5 سنوات من الدراسة، 3 سنوات من الإبحار، 9 سنوات من التصوير." document.write(txt2. تطابق (reg4) + "
");

نظرة سريعة

الرموز بين قوسين مربعين

باستخدام الأقواس المربعة [كيو]يمكنك تحديد مجموعة من الأحرف للبحث عنها.

الحرف ^ الموجود قبل مجموعة الأحرف الموجودة بين قوسين مربعين [^كيلوواط]يشير إلى أنك بحاجة إلى البحث عن كافة الأحرف الأبجدية باستثناء الأحرف المحددة.

استخدام الشرطة (-) بين الحروف الموجودة بين قوسين مربعين [أ-ي]يمكنك تحديد نطاق من الأحرف للبحث عنه.

يمكنك أيضًا البحث عن الأرقام باستخدام الأقواس المربعة.

// قم بتعيين التعبير العادي reg1 reg1=/\sko[tdm]\s/g; // تعيين سلسلة نصية txt1 txt1=" رمز جديلة القط خزانة ذات أدراج com Carpet "; // باستخدام التعبير العادي reg1، ابحث عن السلسلة txt1 document.write(txt1.match(reg1) + "
"); reg2=/\sslo[^tg]/g; txt2=" مقطع الفيل فتحة "; document.write(txt2.match(reg2) + "
"); reg3=//g; txt3="5 سنوات من الدراسة، 3 سنوات من السباحة، 9 سنوات من الرماية"; document.write(txt3.match(reg3));

نظرة سريعة

محددو الكمية

محدد الكمية- هذا بناء يسمح لك بتحديد عدد المرات التي يجب أن تظهر فيها الشخصية أو مجموعة الأحرف السابقة في المباراة.

بناء الجملة:

// يجب أن يحدث الحرف السابق x - مرات (خ)// يجب أن يحدث الحرف السابق من x إلى y مرات شاملة (س، ص)// يجب أن يظهر الحرف السابق × مرات على الأقل (خ،)// يحدد أن الحرف السابق يجب أن يتكرر 0 مرة أو أكثر * // يحدد أن الحرف السابق يجب أن يتكرر مرة واحدة أو أكثر + // يحدد أن الحرف السابق يجب أن يحدث 0 أو 1 مرة ?


// حدد التعبير العادي rv1 rv1=/ko(5)shka/g // حدد التعبير العادي rv2 rv2=/ko(3,)shka/g // حدد التعبير العادي rv3 rv3=/ko+shka/g // تحديد التعبير العادي rv4 rv4=/ko?shka/g // تعيين التعبير العادي rv5 rv5=/ko*shka/g // يظهر الخط العريض مكان العثور على التطابقات في النص عند استخدام // التعبير rv1: kshka cat kooshka koooshka kooooshka kooooshka kooooooshka kooooooshka // يشير الخط العريض إلى المكان الذي سيتم العثور فيه على التطابقات في النص عند استخدام تعبير // rv2: kshka cat kooshka كووشكا كووشكا كوووووووشكا كوووووووشكا كوووووووشكا// يشير الخط الغامق إلى المكان الذي سيتم العثور فيه على التطابقات في النص عند استخدام // تعبير rv3: kshka القط كوشكا كووشكا كووشكا كووشكا كوووووووشكا كوووووووشكا// يشير الخط الغامق إلى المكان الذي سيتم العثور فيه على المطابقات في النص عند استخدام تعبير rv4: kshka cat kooshka koooshka kooooshka koooooshka koooooshka kooooooshka // يشير الخط العريض إلى المكان الذي سيتم العثور فيه على المطابقات في النص عند استخدام تعبير // rv5: kshka القط كووشكا كووشكا كووشكا كووشكا كووشكا كوووووووشكا

ملحوظة:إذا كنت تريد استخدام أي حرف خاص (مثل . * + ? أو ()) مثل الحرف العادي، فيجب عليك وضع \ أمامه.

باستخدام الأقواس

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

على سبيل المثال، التعبير العادي /(Dmitry)\sVasiliev/ سوف يجد السلسلة "Dmitry Vasiliev" ويتذكر السلسلة الفرعية "Dmitry".

في المثال أدناه، نستخدم طريقة الاستبدال () لتغيير ترتيب الكلمات في النص. نحن نستخدم $1 و$2 للوصول إلى التطابقات المخزنة.

var regexp = /(ديمتري)\s(فاسيلييف)/; var text = "ديمتري فاسيليف"; فار newtext = text.replace(regexp, "$2 $1"); document.write(newtext);

نظرة سريعة

يمكن استخدام الأقواس لتجميع الأحرف قبل محددات الكمية.

RegExp الجديد (النمط [، الأعلام])

التعبير العادي ADVANCE

ومن المعروف أن ويفضل بناء الجملة الحرفي(/اختبار/ط).

إذا لم يكن التعبير العادي معروفًا مسبقًا، فمن الأفضل إنشاء تعبير عادي (في سلسلة أحرف) باستخدام المنشئ (RegExp الجديد).

لكن انتبه، نظرًا لأن "علامة الشرطة المائلة" \ تلعب دور تبديل التعليمات البرمجية، فيجب كتابتها مرتين في السلسلة الحرفية (RegExp الجديد): \\

أعلام

أتجاهل الحالة عند المطابقة

المطابقة العامة g، على عكس المطابقة المحلية (افتراضيًا، تتطابق فقط مع المثيل الأول للنمط)، تسمح بمطابقات جميع مثيلات النمط

العاملين

ماذا كيف وصف الاستخدام
أنا علَم لا ريج. تعبير غير حساس لحالة الأحرف /testik/i
ز علَم بحث عالمي /testik/g
م علَم يسمح بالمطابقة مع العديد من السلاسل التي يمكن الحصول عليها من منطقة النص
مشغل فئة الأحرف مطابقة مجموعة الأحرف - أي حرف في النطاق من a إلى z؛
^ مشغل علامة الإقحام يستثني [^a-z] - أي حرف باستثناء الأحرف الموجودة في النطاق من a إلى z؛
- مشغل الواصلة تشير إلى نطاق القيم، شاملة - أي حرف في النطاق من a إلى z؛
\ عامل الهروب يفلت من أي حرف التالية \\
^ بدء مطابقة المشغل يجب أن تتم مطابقة الأنماط في البداية /^testik/g
$ عامل نهاية المطابقة يجب أن تتم مطابقة الأنماط في النهاية /testik$/ز
? المشغل أو العامل؟ يجعل الشخصية اختيارية /ر؟ إست/ز
+ المشغل + /t+est/g
+ المشغل + يجب أن يكون الرمز موجودًا مرة واحدة أو عدة مرات /t+est/g
* المشغل أو العامل * يجب أن يكون الرمز موجودًا مرة واحدة أو بشكل متكرر أو يكون غائبًا تمامًا /t+est/g
{} المشغل أو العامل() تعيين عدد ثابت من تكرار الأحرف /ر(4)إست/ز
{,} المشغل أو العامل (،) ضبط عدد تكرارات الرمز ضمن حدود معينة /ر(4,9)إست/ز

فئات الأحرف المحددة مسبقًا

عضو محدد مسبقا مقارنة
\ ر مساحة أفقية
ترجمة الخط
. أي حرف باستثناء تغذية السطر
أي رقم عاشر وهو ما يعادله
أي حرف بخلاف الرقم العاشر، وهو ما يعادل [^0-9]
أي حرف (أرقام وحروف وشرطات سفلية) مكافئ
أي حرف بخلاف الأرقام والحروف والشرطات السفلية، وهو ما يعادل [^A-Za-z0-9]
أي حرف الفضاء
أي حرف باستثناء الفضاء
حدود الكلمة
ليس حدود الكلمة، بل داخلها. جزء

التجميع()

إذا كنت تريد تطبيق عامل تشغيل مثل + (/(abcd)+/) على مجموعة من الأعضاء، فيمكنك استخدام الأقواس () .

التثبيتات

يسمى جزء التعبير العادي الموجود بين قوسين (). تثبيت.

خذ بعين الاعتبار المثال التالي:

/^()ك\1/

\1 ليس أي حرف من a , b , c .
\1 هو أي حرف يبدأ تطابق الحرف الأول. أي أن الحرف الذي يطابق \1 يكون غير معروف حتى يتم حل التعبير العادي.

مجموعات غير ثابتة

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

لذلك، ل منع التثبيتقبل قوس الافتتاح يجب عليك وضع: ?:

شارع = "

مرحبًا عالم!
"؛ وجدت = str.match(/<(?:\/?)(?:\w+)(?:[^>]*?)>/i); console.log("وجدت بدون إصلاح:"، وجدت); // [ "
" ]

وظيفة الاختبار

التعبير العادي.test()

تتحقق وظيفة الاختبار مما إذا كان التعبير العادي يطابق السلسلة (str). إرجاع إما صحيح أو خطأ.

مثال الاستخدام:

جافا سكريبت

كود الوظيفةF(str)( return /^\d(5)-\d(2)/.test(str); ) //console.log(codeF("12345-12ss")); // صحيح //console.log(codeF("1245-12ss")); // خطأ شنيع

وظيفة المباراة

str.match(regexp)

تقوم دالة المطابقة بإرجاع مصفوفة من القيم أو فارغة في حالة عدم العثور على تطابقات. علامة: إذا كان التعبير العادي لا يحتوي على علامة g (لإجراء بحث عام)، فسيقوم أسلوب المطابقة بإرجاع المطابقة الأولى في السلسلة، وكما يتبين من المثال، في مجموعة من التطابقات التثبيتات تقع(جزء من التعبير العادي بين قوسين).

جافا سكريبت

str = "للحصول على معلومات، يرجى الرجوع إلى: الفصل 3.4.5.1"; re = /chapter (\d+(\.\d)*)/i // مع الالتزامات (بدون علامة عامة) Found = str.match(re) console.log(found); // ["الفصل 3.4.5.1"، "3.4.5.1"، ".1"]

إذا قمت بتزويد طريقة match() بتعبير عادي عام (مع علامة g)، فسيتم إرجاع مصفوفة أيضًا، ولكن مع المباريات العالمية. أي أنه لا يتم إرجاع النتائج المسجلة.

جافا سكريبت

str = "للحصول على معلومات، يرجى الرجوع إلى: الفصل 3.4.5.1، الفصل 7.5"; re = /chapter (\d+(\.\d)*)/ig // بدون التزامات - تم العثور عليه عالميًا = str.match(re) console.log(found); // ["الفصل 3.4.5.1"، "الفصل 7.5"]

وظيفة إكسيك

regexp.exec(شارع)

تتحقق الدالة exec مما إذا كان التعبير العادي يطابق سلسلة (str). إرجاع مجموعة من النتائج (مع الالتزامات) أو null . يحدث كل استدعاء لاحق لـ exec (على سبيل المثال، عند استخدام while) (من خلال تحديث exec تلقائيًا لفهرس نهاية البحث الأخير، lastIndex)، وينتقل إلى المطابقة العامة التالية (إذا تم تحديد علامة g).

جافا سكريبت

فار أتش تي أم أل = "
بام! متشرد!
"؛ فار ريج = /<(\/?)(\w+)([^>]*?)>/g; //console.log(reg.exec(html)); // ["
"، ""، "div"، " class = "test""] while((match = reg.exec(html)) !== null)( console.log(reg.exec(html)); ) /* [" "، ""، "ب"، ""] [" "، ""، "م"، ""] ["
"، "/"، "div"، ""] */

بدون العلم العالمي، تعمل طريقتا match وexec بشكل متماثل. أي أنهم يعيدون مصفوفة مع أول تطابق عالمي والتزامات.

جافا سكريبت

// تطابق فار html = "
بام! متشرد!
"؛ فار ريج = /<(\/?)(\w+)([^>]*?)>/; // بدون console.log العمومي(html.match(reg)); // ["
"، ""، "div"، " class = "test""] // exec var html = "
بام! متشرد!
"؛ فار ريج = /<(\/?)(\w+)([^>]*?)>/; // بدون console.log العمومي(reg.exec(html)); // ["
"، ""، "div"، " class = "اختبار""]

استبدال الوظيفة

str.replace(regexp, newSubStr|وظيفة)
  • التعبير العادي - ريج. تعبير؛
  • newSubStr - السلسلة التي تم تغيير التعبير الموجود في النص إليها؛
  • الوظيفة - يتم استدعاؤها لكل تطابق يتم العثور عليه باستخدام قائمة متغيرة من المعلمات (تذكر أن البحث الشامل في سلسلة يعثر على جميع مثيلات تطابق النمط).

تعمل القيمة المرجعة لهذه الوظيفة كبديل.

معلمات الوظيفة:

  • 1 - أكمل السلسلة الفرعية المتطابقة.
  • 2 - معنى مجموعات الأقواس (التثبيتات).
  • 3 - فهرس (موضع) المطابقة في السلسلة المصدر.
  • 4 - سلسلة المصدر.

لا تغير الطريقة سلسلة الاستدعاء، ولكنها ترجع سلسلة جديدة بعد استبدال التطابقات. لإجراء بحث واستبدال عالمي، استخدم regexp مع العلامة g.

"GHGHGHGTTTT".replace(//g,K"); //"ككككككككك"

جافا سكريبت

وظيفة upLetter(allStr,letter) (return letter.toUpperCase();) var res = "border-top-width".replace(/-(\w)/g, upLetter); console.log(res); //borderTopWidth

بعض الأشخاص، عندما يواجهون مشكلة ما، يفكرون: "أوه، سأستخدم التعبيرات العادية." الآن لديهم مشكلتين.
جيمي زاوينسكي

قال يوان ما، "إن قطع الخشب عبر حبيبات الخشب يتطلب الكثير من القوة. يستغرق الأمر الكثير من التعليمات البرمجية للبرمجة عبر بنية المشكلة.
المعلم يوان ما، "كتاب البرمجة"

أدوات وتقنيات البرمجة تبقى على قيد الحياة وتنتشر بطريقة تطورية فوضوية. في بعض الأحيان، لا يبقى الأشخاص الجميلون والرائعون، ولكن ببساطة أولئك الذين يعملون بشكل جيد بما فيه الكفاية في مجالهم - على سبيل المثال، إذا تم دمجهم في تقنية أخرى ناجحة.

في هذا الفصل، سنناقش مثل هذه الأداة - التعبيرات العادية. هذه طريقة لوصف الأنماط في بيانات السلسلة. يقومون بإنشاء لغة صغيرة مستقلة مضمنة في JavaScript والعديد من اللغات والأدوات الأخرى.

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

إنشاء تعبير عادي

عادي - نوع الكائن. يمكن إنشاؤه عن طريق استدعاء مُنشئ RegExp، أو عن طريق كتابة القالب المطلوب، محاطًا بخطوط مائلة.

var re1 = new RegExp("abc"); فار re2 = /abc/;

يمثل كلا التعبيرين النمطيين نفس النمط: الحرف "a" متبوعًا بالحرف "b" متبوعًا بالحرف "c".

إذا كنت تستخدم منشئ RegExp، فسيتم كتابة النمط كسلسلة عادية، لذلك يتم تطبيق جميع القواعد المتعلقة بالخطوط المائلة العكسية.

الإدخال الثاني، حيث يكون النمط بين الخطوط المائلة، يعامل الخطوط المائلة العكسية بشكل مختلف. أولاً، نظرًا لأن النمط ينتهي بشرطة مائلة للأمام، فنحن بحاجة إلى وضع شرطة مائلة للخلف قبل الشرطة المائلة للأمام التي نريد تضمينها في نمطنا. بالإضافة إلى ذلك، سيتم الحفاظ على الخطوط المائلة العكسية التي لا تشكل جزءًا من أحرف خاصة مثل \n (بدلاً من تجاهلها كما هو الحال في السلاسل)، وسوف تغير معنى النمط. بعض الأحرف، مثل علامة الاستفهام أو علامة الزائد، لها معنى خاص في التعبيرات العادية، وإذا كنت بحاجة إلى العثور على مثل هذا الحرف، فيجب أيضًا أن يسبقه شرطة مائلة عكسية.

var EighteenPlus = /ثمانية عشر\+/;

لمعرفة الأحرف التي يجب أن تسبقها شرطة مائلة، يتعين عليك التعرف على قائمة بجميع الأحرف الخاصة في التعبيرات العادية. هذا غير ممكن حتى الآن، لذلك عندما تكون في شك، ما عليك سوى وضع شرطة مائلة عكسية أمام أي حرف ليس حرفًا أو رقمًا أو مسافة.

التحقق من وجود مباريات

النظاميون لديهم عدة طرق. أبسط واحد هو الاختبار. إذا قمت بتمرير سلسلة، فسوف تُرجع قيمة منطقية تشير إلى ما إذا كانت السلسلة تحتوي على تكرار للنمط المحدد.

Console.log(/abc/.test("abcde")); // → صحيح console.log(/abc/.test("abxde")); // → خطأ

التسلسل العادي الذي يتكون فقط من أحرف غير خاصة هو ببساطة تسلسل من هذه الأحرف. إذا كان abc في أي مكان في السطر الذي نختبره (وليس فقط في البداية)، فسيعود الاختبار صحيحًا.

أبحث عن مجموعة من الشخصيات

يمكنك أيضًا معرفة ما إذا كانت السلسلة تحتوي على abc باستخدام ملف IndexOf. تتيح لك الأنماط العادية المضي قدمًا وإنشاء أنماط أكثر تعقيدًا.

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

كلا التعبيرين موجودان في أسطر تحتوي على رقم.

Console.log(//.test("في عام 1992")); // → صحيح console.log(//.test("في 1992")); // → صحيح

بين قوسين مربعين، يتم استخدام شرطة بين حرفين لتحديد نطاق من الأحرف، حيث يتم تحديد التسلسل بواسطة ترميز Unicode. الأحرف من 0 إلى 9 موجودة في صف واحد فقط (الرموز من 48 إلى 57)، لذا فهي تلتقطها جميعًا وتطابق أي رقم.

تحتوي العديد من مجموعات الأحرف على اختصارات مدمجة خاصة بها.

\d أي رقم
\w حرف أبجدي رقمي
\s حرف المسافة البيضاء (مسافة، علامة تبويب، سطر جديد، إلخ.)
\D ليس رقما
\W ليس حرفًا أبجديًا رقميًا
\S ليس حرف مسافة بيضاء
. أي حرف باستثناء تغذية السطر

وبالتالي، يمكنك ضبط تنسيق التاريخ والوقت مثل 30/01/2003 15:20 بالتعبير التالي:

var dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/; console.log(dateTime.test("30-01-2003 15:20")); // → صحيح console.log(dateTime.test("30 يناير 2003 15:20")); // → خطأ

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

يمكن أيضًا استخدام الخطوط المائلة العكسية بين قوسين مربعين. على سبيل المثال، [\d.] يعني أي رقم أو فترة. لاحظ أن النقطة الموجودة داخل الأقواس المربعة تفقد معناها الخاص وتصبح مجرد نقطة. وينطبق الشيء نفسه على الأحرف الخاصة الأخرى، مثل +.

يمكنك عكس مجموعة من الأحرف - أي أنك تحتاج إلى العثور على أي حرف باستثناء تلك الموجودة في المجموعة - عن طريق وضع علامة ^ مباشرة بعد قوس الفتح المربع.

var notBinary = /[^01]/; console.log(notBinary.test("1100100010100110")); // → false console.log(notBinary.test("1100100010200110")); // → صحيح

تكرار أجزاء من القالب

نحن نعرف كيفية العثور على رقم واحد. ماذا لو أردنا إيجاد العدد الصحيح - سلسلة مكونة من رقم واحد أو أكثر؟

إذا وضعت علامة + بعد شيء ما في التسلسل المنتظم، فهذا يعني أنه يمكن تكرار هذا العنصر أكثر من مرة. /\d+/ يعني رقمًا واحدًا أو أكثر.

Console.log(/"\d+"/.test(""123"")); // → صحيح console.log(/"\d+"/.test("""")); // → false console.log(/"\d*"/.test(""123"")); // → صحيح console.log(/"\d*"/.test("""")); // → صحيح

العلامة النجمية * لها نفس المعنى تقريبًا، ولكنها تسمح بتكرار النمط صفر مرة. إذا كان هناك شيء متبوع بعلامة النجمة، فهذا يعني عدم منع النمط من التواجد في السطر - فهو يظهر هناك صفر مرة.

علامة الاستفهام تجعل جزءًا من النموذج اختياريًا، مما يعني أنه يمكن أن يحدث صفرًا أو مرة واحدة. في المثال التالي، قد يظهر الحرف u، لكن النمط يتطابق حتى عندما لا يظهر.

فار الجار = /neighbou?r/; console.log(neighbor.test("neighbor")); // → صحيح console.log(neighbor.test("neighbor")); // → صحيح

يتم استخدام الأقواس المتعرجة لتحديد العدد الدقيق للمرات التي يجب أن يحدث فيها النمط. (4) بعد العنصر يعني أنه يجب أن يظهر 4 مرات في السطر. يمكنك أيضًا تحديد فجوة: (2،4) تعني أن العنصر يجب أن يتكرر مرتين على الأقل ولا يزيد عن 4 مرات.

نسخة أخرى من تنسيق التاريخ والوقت، حيث يُسمح بالأيام والأشهر والساعات المكونة من رقم واحد أو رقمين. كما أنها أكثر قابلية للقراءة قليلاً.

var dateTime = /\d(1,2)-\d(1,2)-\d(4) \d(1,2):\d(2)/; console.log(dateTime.test("30-1-2003 8:45")); // → صحيح

يمكنك استخدام المساحات المفتوحة عن طريق حذف أحد الأرقام. (،5،) تعني أن النمط يمكن أن يحدث من صفر إلى خمس مرات، و(5،) تعني من خمس مرات أو أكثر.

تجميع التعبيرات الفرعية

لاستخدام عوامل التشغيل * أو + على عناصر متعددة في وقت واحد، يمكنك استخدام الأقواس. يعتبر جزء التعبير النمطي الموجود بين قوسين عنصرًا واحدًا من وجهة نظر المشغلين.

var CartoonCrying = /boo+(hoo+)+/i; console.log(cartoonCrying.test("Boohoooohoohooo")); // → صحيح

الزائد الأول والثاني ينطبق فقط على الثاني o في الكلمتين boo وhoo. الثالث + يشير إلى المجموعة بأكملها (hoo+)، ويجد واحدًا أو أكثر من هذه التسلسلات.

الحرف i الموجود في نهاية التعبير يجعل التعبير العادي غير حساس لحالة الأحرف - بحيث يتطابق B مع b.

المباريات والمجموعات

طريقة الاختبار هي أبسط طريقة للتحقق من التعبيرات العادية. يخبرك فقط ما إذا تم العثور على تطابق أم لا. لدى العناصر النظامية أيضًا طريقة exec، والتي ستعيد القيمة null إذا لم يتم العثور على أي شيء، وتعيد كائنًا يحتوي على معلومات حول المطابقة.

var match = /\d+/.exec("واحد اثنان 100"); console.log(match); // → ["100"] console.log(match.index); // → 8

يحتوي الكائن الذي تم إرجاعه بواسطة exec على خاصية فهرس، والتي تحتوي على رقم الحرف الذي حدثت منه المطابقة. بشكل عام، يبدو الكائن كمصفوفة من السلاسل، حيث يكون العنصر الأول هو السلسلة التي تم التحقق من تطابقها. في مثالنا، سيكون هذا هو تسلسل الأرقام الذي كنا نبحث عنه.

السلاسل لها طريقة مطابقة تعمل بنفس الطريقة تقريبًا.

Console.log("واحد اثنان 100".match(/\d+/)); // → ["100"]

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

var quoteText = /"([^"]*)"/; console.log(quotedText.exec("قالت "hello"")); // → [""hello"", "hello"]

عندما لا يتم العثور على مجموعة على الإطلاق (على سبيل المثال، إذا كانت متبوعة بعلامة استفهام)، يكون موضعها في المصفوفة غير محدد. إذا تطابقت المجموعة عدة مرات، فستكون المباراة الأخيرة فقط في المصفوفة.

Console.log(/bad(ly)?/.exec("bad")); // → ["سيء"، غير محدد] console.log(/(\d)+/.exec("123")); // → ["123"، "3"]

المجموعات مفيدة لاسترداد أجزاء من السلاسل. إذا لم نكن نريد فقط التحقق مما إذا كانت السلسلة تحتوي على تاريخ، ولكننا نستخرجها وننشئ كائنًا يمثل التاريخ، فيمكننا وضع تسلسل الأرقام بين قوسين واختيار التاريخ من نتيجة exec.

لكن أولاً، القليل من الاستطراد الذي سنتعلم فيه الطريقة المفضلة لتخزين التاريخ والوقت في JavaScript.

نوع التاريخ

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

Console.log(new Date()); // → الأحد 09 نوفمبر 2014 00:07:57 بتوقيت جرينتش+0300 (توقيت وسط أوروبا)

يمكنك أيضًا إنشاء كائن يحتوي على وقت معين

Console.log(new Date(2015, 9, 21)); // → الأربعاء 21 أكتوبر 2015 00:00:00 بتوقيت جرينتش+0300 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → الأربعاء 09 ديسمبر 2009 12:59:59 بتوقيت جرينتش+0300 (توقيت وسط أوروبا)

تستخدم JavaScript تقليدًا حيث تبدأ أرقام الأشهر بصفر وتبدأ أرقام اليوم بواحد. هذا غبي ومثير للسخرية. احترس.

تعتبر الوسيطات الأربع الأخيرة (الساعات والدقائق والثواني والميلي ثانية) اختيارية ويتم ضبطها على صفر في حالة فقدانها.

يتم تخزين الطوابع الزمنية على هيئة عدد المللي ثانية التي مرت منذ بداية عام 1970. في الأوقات التي سبقت عام 1970، تم استخدام الأرقام السالبة (وهذا بسبب اصطلاح وقت Unix الذي تم إنشاؤه في ذلك الوقت تقريبًا). تقوم طريقة getTime الخاصة بكائن التاريخ بإرجاع هذا الرقم. إنها كبيرة بشكل طبيعي.
console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → الخميس 19 ديسمبر 2013 00:00:00 بتوقيت جرينتش+0100 (توقيت وسط أوروبا)

إذا أعطيت مُنشئ التاريخ وسيطة واحدة، فسيتم التعامل معها على هذا العدد من المللي ثانية. يمكنك الحصول على قيمة المللي ثانية الحالية عن طريق إنشاء كائن Date واستدعاء الأسلوب getTime، أو عن طريق استدعاء الدالة Date.now.

يحتوي كائن التاريخ على أساليب getFullYear، وgetMonth، وgetDate، وgetHours، وgetMinutes، وgetSeconds لاسترداد مكوناته. هناك أيضًا طريقة getYear التي تُرجع رمزًا مكونًا من رقمين عديم الفائدة مثل 93 أو 14.

من خلال وضع الأجزاء ذات الصلة من القالب بين قوسين، يمكننا إنشاء كائن تاريخ مباشرة من السلسلة.

دالة findDate(string) ( var dateTime = /(\d(1,2))-(\d(1,2))-(\d(4))/; var match = dateTime.exec(string); return تاريخ جديد (رقم (تطابق)، رقم (تطابق) - 1، رقم (تطابق) ) console.log(findDate("30-1-2003")); // → الخميس 30 يناير 2003 00:00:00 بتوقيت جرينتش+0100 (توقيت وسط أوروبا)

حدود الكلمة والخط

لسوء الحظ، سيتمكن findDate من استخراج التاريخ الذي لا معنى له 00-1-3000 من السلسلة "100-1-30000". يمكن أن تحدث المطابقة في أي مكان في السلسلة، لذلك في هذه الحالة ستبدأ ببساطة عند الحرف الثاني وتنتهي عند الحرف الثاني قبل الأخير.

إذا أردنا فرض المطابقة على السلسلة بأكملها، فإننا نستخدم علامتي ^ و$. ^ يطابق بداية السطر، و $ يطابق النهاية. لذلك، /^\d+$/ يطابق سلسلة تحتوي على رقم واحد فقط أو أكثر، /^!/ يطابق سلسلة تبدأ بعلامة تعجب، و /x^/ لا يطابق أي سلسلة (لا يمكن أن يكون هناك x).

من ناحية أخرى، إذا أردنا فقط التأكد من أن التاريخ يبدأ وينتهي عند حد الكلمة، فإننا نستخدم العلامة \b. يمكن أن يكون حد الكلمة هو بداية السطر أو نهايته، أو أي مكان في السطر حيث يوجد حرف أبجدي رقمي \w على أحد الجانبين وحرف غير أبجدي رقمي على الجانب الآخر.

Console.log(/cat/.test("تسلسل")); // → صحيح console.log(/\bcat\b/.test("concatenate")); // → خطأ

لاحظ أن تسمية الحدود ليست رمزًا. إنه ببساطة قيد يعني أن التطابق يحدث فقط في حالة استيفاء شرط معين.

قوالب مع الاختيار

لنفترض أنك بحاجة إلى معرفة ما إذا كان النص لا يحتوي على رقم فقط، بل يحتوي على رقم متبوعًا بخنزير أو بقرة أو دجاج بصيغة المفرد أو الجمع.

سيكون من الممكن كتابة ثلاثة تعبيرات عادية والتحقق منها واحدة تلو الأخرى، ولكن هناك طريقة أفضل. الرمز | يشير إلى الاختيار بين الأنماط الموجودة على يساره وعلى يمينه. ويمكننا أن نقول ما يلي:

var AnimalCount = /\b\d+ (خنزير|بقرة|دجاج)s?\b/; console.log(animalCount.test("15 خنزير")); // → صحيح console.log(animalCount.test("15 دجاج خنزير")); // → خطأ

تحدد الأقواس جزء النموذج الذي يتم تطبيق | عليه، ويمكن وضع العديد من عوامل التشغيل واحدًا تلو الآخر للإشارة إلى الاختيار من بين أكثر من خيارين.

محرك البحث

يمكن اعتبار التعبيرات العادية بمثابة مخططات انسيابية. ويصف الرسم البياني التالي مثالا حديثا للماشية.

يتطابق التعبير مع سلسلة إذا كان من الممكن العثور على مسار من الجانب الأيسر من الرسم التخطيطي إلى اليمين. نتذكر الموضع الحالي في السطر، وفي كل مرة نمر عبر المستطيل، نتحقق من أن جزء الخط الذي يلي موضعنا فيه مباشرة يطابق محتويات المستطيل.

هذا يعني أن التحقق من تطابق حرفنا العادي في السلسلة "الخنازير الثلاثة" عند المرور عبر المخطط الانسيابي يبدو كما يلي:

في الموضع 4 يوجد حد للكلمة، ونمرر المستطيل الأول
- بدءًا من الموضع الرابع نجد الرقم ونمر عبر المستطيل الثاني
- في الموضع 5، يُغلق أحد المسارين أمام المستطيل الثاني، ويتجه الثاني إلى المستطيل بمسافة. لدينا مساحة وليس رقمًا، ونختار المسار الثاني.
- الآن نحن في الموضع 6، بداية "الخنازير"، وعند التفرع الثلاثي للمسارات. ليس هناك "بقرة" أو "دجاجة" في الخط، ولكن هناك "خنزير"، لذلك اخترنا هذا المسار.
- في الموضع 9 بعد الشوكة الثلاثية، يتجاوز المسار "s" ويذهب إلى مستطيل حد الكلمة الأخيرة، ويمر الثاني عبر "s". لدينا حرف "s" لذا نذهب إلى هناك.
- في الموضع 10 نحن في نهاية السطر، ولا يمكن أن يتطابق إلا مع حد الكلمة. نهاية الخط تعتبر الحد، ونمر بالمستطيل الأخير. والآن نجحنا في العثور على القالب الخاص بنا.

في الأساس، الطريقة التي تعمل بها التعبيرات العادية هي أن الخوارزمية تبدأ في بداية السلسلة وتحاول العثور على تطابق هناك. في حالتنا، هناك حد للكلمة، فتتجاوز المستطيل الأول - لكن لا يوجد رقم هناك، فتتعثر في المستطيل الثاني. ثم ينتقل إلى الحرف الثاني في السلسلة، ويحاول العثور على تطابق هناك... وهكذا حتى يجد تطابقًا أو يصل إلى نهاية السلسلة، وفي هذه الحالة لا يتم العثور على تطابق.

العمولات

التعبير العادي /\b(+b|\d+|[\da-f]h)\b/ يطابق إما رقمًا ثنائيًا متبوعًا بـ b، أو رقمًا عشريًا بدون لاحقة، أو رقمًا سداسيًا عشريًا (الأرقام من 0 إلى 9) أو الرموز من a إلى h)، متبوعة بـ h. الرسم البياني ذو الصلة:

عند البحث عن تطابق، قد يحدث أن تأخذ الخوارزمية المسار العلوي (الرقم الثنائي)، حتى لو لم يكن هناك رقم كهذا في السلسلة. إذا كان هناك سطر "103"، على سبيل المثال، فمن الواضح أنه فقط بعد الوصول إلى الرقم 3 ستدرك الخوارزمية أنه على المسار الخاطئ. بشكل عام، السطر يطابق التسلسل العادي، ولكن ليس في هذا الموضوع.

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

تتوقف الخوارزمية بمجرد العثور على تطابق كامل. وهذا يعني أنه حتى لو كانت هناك عدة خيارات مناسبة، فسيتم استخدام واحد منها فقط (بالترتيب الذي تظهر به في التسلسل العادي).

يحدث التراجع عند استخدام عوامل التكرار مثل + و*. إذا بحثت عن /^.*x/ في السلسلة "abcxe"، فسيحاول جزء regex.* استهلاك السلسلة بأكملها. ستدرك الخوارزمية بعد ذلك أنها تحتاج أيضًا إلى "x". نظرًا لعدم وجود "x" بعد نهاية السلسلة، ستحاول الخوارزمية البحث عن تطابق من خلال إرجاع حرف واحد للخلف. بعد abcx أيضًا لا يوجد x، ثم يتراجع مرة أخرى، هذه المرة إلى السلسلة الفرعية abc. وبعد السطر، يجد x ويبلغ عن تطابق ناجح، في المواضع من 0 إلى 4.

يمكنك كتابة روتين منتظم يؤدي إلى تراجعات متعددة. تحدث هذه المشكلة عندما يتطابق النمط مع الإدخال بعدة طرق مختلفة. على سبيل المثال، إذا ارتكبنا خطأً عند كتابة التعبير العادي للأرقام الثنائية، فقد نكتب عن طريق الخطأ شيئًا مثل /(+)+b/.

إذا كانت الخوارزمية تبحث عن مثل هذا النمط في سلسلة طويلة من 0 و1 لا تحتوي على "b" في النهاية، فسوف تمر أولاً عبر الحلقة الداخلية حتى نفاد الأرقام. ثم سيلاحظ أنه لا يوجد "ب" في النهاية، وسوف يتراجع عن موضع واحد، ويمر عبر الحلقة الخارجية، ويستسلم مرة أخرى، ويحاول العودة إلى موضع آخر على طول الحلقة الداخلية... وسيستمر للبحث بهذه الطريقة باستخدام كلا الحلقتين. أي أن مقدار العمل مع كل حرف في السطر سوف يتضاعف. حتى بالنسبة لعشرات الشخصيات، سيستغرق العثور على تطابق وقتًا طويلاً جدًا.

استبدال الطريقة

تحتوي السلاسل على طريقة استبدال يمكنها استبدال جزء من سلسلة بسلسلة أخرى.

Console.log("dad".replace("p", "m")); // → الخريطة

يمكن أن تكون الوسيطة الأولى أيضًا تعبيرًا عاديًا، وفي هذه الحالة يتم استبدال التواجد الأول للتعبير العادي في السطر. عند إضافة الخيار "g" (العالمي) إلى تعبير عادي، يتم استبدال جميع التكرارات، وليس الأول فقط

Console.log("Borobudur".replace(//, "a")); // → باروبودور console.log("Borobudur".replace(//g, "a")); // → بارادار

سيكون من المنطقي تمرير خيار "استبدال الكل" من خلال وسيطة منفصلة، ​​أو من خلال طريقة منفصلة مثل استبدال الكل. لكن للأسف ينتقل الخيار عبر النظام العادي نفسه.

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

Console.log("هوبر، جريس\nمكارثي، جون\nريتشي، دينيس" .replace(/([\w ]+), ([\w ]+)/g, "$2 $1")); // → غريس هوبر // جون مكارثي // دينيس ريتشي

يشير $1 و$2 في سطر الاستبدال إلى مجموعات من الأحرف المحاطة بين قوسين. يتم استبدال $1 بالنص الذي يطابق المجموعة الأولى، و$2 بالمجموعة الثانية، وهكذا حتى 9 $. المطابقة بأكملها موجودة في المتغير $&.

يمكنك أيضًا تمرير دالة باعتبارها الوسيطة الثانية. لكل استبدال، سيتم استدعاء دالة ستكون وسيطاتها هي المجموعات التي تم العثور عليها (والجزء المطابق بالكامل من السلسلة)، وسيتم إدراج نتيجتها في سطر جديد.

مثال بسيط:

var s = "وكالة المخابرات المركزية ومكتب التحقيقات الفيدرالي"; console.log(s.replace(/\b(fbi|cia)\b/g, function(str) ( return str.toUpperCase(); ))); // → وكالة المخابرات المركزية ومكتب التحقيقات الفيدرالي

إليك واحدة أكثر إثارة للاهتمام:

مخزون فار = "1 ليمونة، 2 ملفوف، و101 بيضة"؛ دالة minusOne(match, المبلغ, الوحدة) ( المبلغ = الرقم(المبلغ) - 1; إذا (المبلغ == 1) // بقي واحد فقط، قم بإزالة "s" في النهاية Unit =unit.slice(0,unit. الطول - 1)؛ وإلا إذا (المبلغ == 0) المبلغ = "لا"؛ مبلغ الإرجاع + "" + الوحدة) console.log(stock.replace(/(\d+) (\w+)/g, minusOne) ); // → بدون ليمون، 1 ملفوف، و100 بيضة

يأخذ الكود سلسلة، ويبحث عن جميع تكرارات الأرقام متبوعة بكلمة، ويعيد سلسلة مع تقليل كل رقم بمقدار واحد.

تنتقل المجموعة (\d+) إلى وسيطة المبلغ، وتنتقل (\w+) إلى وسيطة الوحدة. تقوم الدالة بتحويل المبلغ إلى رقم - وهذا يعمل دائمًا، لأن النمط الخاص بنا هو \d+. ثم يقوم بإجراء تغييرات على الكلمة، في حالة وجود عنصر واحد فقط متبقي.

جشع

من السهل استخدام الاستبدال لكتابة دالة تزيل جميع التعليقات من كود JavaScript. ها هي المحاولة الأولى:

الدالة stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); ) console.log(stripComments("1 + /* 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// عشرة!")); // → س = 10؛ console.log(stripComments("1 /* أ */+/* ب */ 1")); // → 1 1

يتطابق الجزء الموجود قبل عامل التشغيل "أو" مع شرطتين متبوعتين بأي عدد من الأحرف باستثناء الأسطر الجديدة. الجزء الذي يزيل التعليقات متعددة الأسطر أكثر تعقيدًا. نستخدم [^]، أي. أي حرف غير فارغ كوسيلة للعثور على أي حرف. لا يمكننا استخدام نقطة لأن التعليقات المحظورة تستمر في سطر جديد، ولا يتطابق حرف السطر الجديد مع النقطة.

لكن إخراج المثال السابق غير صحيح. لماذا؟

سيحاول الجزء [^]* أولاً التقاط أكبر عدد ممكن من الأحرف. إذا لم يجد الجزء التالي من التسلسل العادي تطابقًا لهذا السبب، فسوف يتراجع حرفًا واحدًا ويحاول مرة أخرى. في المثال، تحاول الخوارزمية الاستيلاء على السطر بأكمله، ثم تتراجع. بعد إرجاع 4 أحرف، سيجد */ في السطر - وهذا ليس ما أردناه. أردنا الحصول على تعليق واحد فقط، وعدم الذهاب إلى نهاية السطر والعثور على التعليق الأخير.

ولهذا السبب، نقول إن عوامل التكرار (+، *، ?، و ()) جشعة، مما يعني أنها تستحوذ أولاً على أكبر قدر ممكن من المعلومات ثم تعود مرة أخرى. إذا وضعت سؤالاً بعد عامل مثل هذا (+?، *?، ??، ()؟)، فسوف يتحول إلى غير جشع، ويبدأ في العثور على أصغر الأحداث الممكنة.

وهذا ما نحتاجه. من خلال إجبار العلامة النجمية على البحث عن التطابقات في أقل عدد ممكن من الأحرف في السطر، فإننا نستهلك كتلة واحدة فقط من التعليقات، وليس أكثر.

الدالة stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*?\*\//g, ""); ) console.log(stripComments("1 /* أ */+/* ب */ 1")); // → 1 + 1

تحدث العديد من الأخطاء عند استخدام العوامل الجشعة بدلاً من العوامل غير الجشعة. عند استخدام عامل التكرار، فكر دائمًا في خيار المشغل غير الجشع أولاً.

إنشاء كائنات RegExp ديناميكيًا

في بعض الحالات، لا يكون النمط الدقيق معروفًا في وقت كتابة الكود. على سبيل المثال، سوف تحتاج إلى البحث عن اسم المستخدم في النص، وإحاطته بشرطة سفلية. نظرًا لأنك لن تعرف الاسم إلا بعد تشغيل البرنامج، فلا يمكنك استخدام علامة الشرطة المائلة.

ولكن يمكنك إنشاء السلسلة واستخدام مُنشئ RegExp. هنا مثال:

اسم فار = "هاري"; var text = "وهاري لديه ندبة على جبهته."; var regexp = new RegExp("\\b(" + name + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → و _Harry_ لديه ندبة على جبهته.

عند إنشاء حدود الكلمات، علينا استخدام الخطوط المائلة المزدوجة لأننا نكتبها بخط عادي، وليس بتعبير عادي به خطوط مائلة للأمام. تحتوي الوسيطة الثانية لـ RegExp على خيارات للتعبيرات العادية - في حالتنا "gi"، أي. عالمية وغير حساسة لحالة الأحرف.

ولكن ماذا لو كان الاسم "dea+hlrd" (إذا كان مستخدمنا كولهاتزكر)؟ ونتيجة لذلك، سوف نحصل على تعبير عادي لا معنى له ولن يجد تطابقات في السلسلة.

يمكننا إضافة خطوط مائلة عكسية قبل أي شخصية لا نحبها. لا يمكننا إضافة خطوط مائلة عكسية قبل الأحرف لأن \b أو \n أحرف خاصة. ولكن يمكنك إضافة خطوط مائلة قبل أي أحرف غير أبجدية رقمية دون أي مشاكل.

اسم فار = "dea+hlrd"; var text = "هذا dea+hlrd يزعج الجميع."; var escaped = name.replace(/[^\w\s]/g, "\\$&"); var regexp = new RegExp("\\b(" + escaped + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → هذا _dea+hlrd_ أزعج الجميع.

طريقة البحث

لا يمكن استخدام الأسلوب IndexOf مع التعبيرات العادية. ولكن هناك طريقة بحث تتوقع فقط التعبير العادي. مثل مؤشر IndexOf، فإنه يُرجع فهرس التواجد الأول، أو -1 في حالة عدم حدوث أي شيء.

Console.log("word".search(/\S/)); // → 2 console.log(" ".search(/\S/)); // → -1

لسوء الحظ، لا توجد طريقة لإخبار الطريقة بالبحث عن تطابق بدءًا من إزاحة معينة (كما يمكنك القيام به باستخدام مؤشر IndexOf). سيكون ذلك مفيدًا.

خاصية الفهرس الأخير

لا يوفر التابع exec أيضًا طريقة ملائمة لبدء البحث من موضع معين في السلسلة. لكنه يعطي وسيلة غير مريحة.

كائن regex له خصائص. واحد منهم هو المصدر الذي يحتوي على سلسلة. وهناك خيار آخر هو lastIndex، الذي يتحكم، في بعض الحالات، في المكان الذي سيبدأ فيه البحث التالي عن الأحداث.

تتضمن هذه الشروط أن الخيار العام g يجب أن يكون موجودًا، وأن يتم البحث باستخدام الأسلوب exec. الحل الأكثر منطقية هو السماح ببساطة بتمرير وسيطة إضافية إلى exec، ولكن المعقولية ليست سمة أساسية لواجهة JavaScript regex.

نمط فار = /y/g; style.lastIndex = 3; فار ماتش = Pattern.exec("xyzzy"); console.log(match.index); // → 4 console.log(pattern.lastIndex); // → 5

إذا كان البحث ناجحًا، فسيقوم استدعاء exec بتحديث خاصية lastIndex للإشارة إلى الموضع بعد التكرار الذي تم العثور عليه. إذا لم يكن هناك نجاح، فسيتم تعيين lastIndex على صفر - تمامًا مثل lastIndex للكائن الذي تم إنشاؤه حديثًا.

عند استخدام متغير عادي عام واستدعاءات exec متعددة، يمكن أن تتسبب تحديثات lastIndex التلقائية هذه في حدوث مشكلات. يمكن لخادمك العادي أن يبدأ البحث من الموضع المتبقي من المكالمة السابقة.

رقم فار = /\d/g; console.log(digit.exec("ها هو: 1")); // → ["1"] console.log(digit.exec("والآن: 1")); // → فارغة

تأثير آخر مثير للاهتمام لخيار g هو أنه يغير كيفية عمل طريقة المطابقة. عند استدعائه باستخدام هذا الخيار، بدلاً من إرجاع مصفوفة مشابهة لنتيجة exec، فإنه يبحث عن كافة تكرارات النمط في السلسلة ويعيد مصفوفة من السلاسل الفرعية التي تم العثور عليها.

Console.log("Banana".match(/an/g)); // → ["أن"، "أن"]

لذا كن حذرًا مع المتغيرات العادية العالمية. الحالات التي تكون هناك حاجة إليها - استبدال المكالمات أو الأماكن التي تستخدم فيها lastIndex على وجه التحديد - ربما تكون جميع الحالات التي يجب استخدامها فيها.

دورات الحدوث

تتمثل المهمة النموذجية في تكرار كل تكرارات النمط في سلسلة ما حتى تتمكن من الوصول إلى كائن المطابقة في نص الحلقة باستخدام lastIndex وexec.

var input = "خط به 3 أرقام... 42 و88."; رقم فار = /\b(\d+)\b/g; مباراة فار؛ بينما (match = number.exec(input)) console.log("تم العثور عليه"، تطابق، "on"، match.index)؛ // → تم العثور على 3 في 14 // تم العثور على 42 في 33 // تم العثور على 88 في 40

إنه يستفيد من حقيقة أن قيمة المهمة هي القيمة التي يتم تعيينها. باستخدام match = re.exec(input) كشرط في حلقة while، فإننا نبحث في بداية كل تكرار، ونخزن النتيجة في متغير، وننهي الحلقة عندما يتم العثور على جميع التطابقات.

تحليل ملفات INI

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

Searchengine=http://www.google.com/search?q=$1 النكاية=9.7 ; يتم وضع فاصلة منقوطة قبل التعليقات؛ يشير كل قسم إلى عدو مختلف fullname=نوع Larry Doe=kindergarten Bull website=http://www.geocities.com/CapeCanaveral/11451 fullname=نوع Gargamel=إخراج المعالج الشرير=/home/marijn/enemies/gargamel

تنسيق الملف الدقيق (والذي يستخدم على نطاق واسع، ويسمى عادة INI) هو كما يلي:

يتم تجاهل الأسطر الفارغة والأسطر التي تبدأ بفاصلة منقوطة
- الخطوط المحصورة بين قوسين مربعين تبدأ قسمًا جديدًا
- الأسطر التي تحتوي على معرف أبجدي رقمي متبوعًا بـ = إضافة إعداد في هذا القسم

كل شيء آخر هو بيانات غير صحيحة.

مهمتنا هي تحويل هذه السلسلة إلى مجموعة من الكائنات، لكل منها خاصية اسم ومجموعة من الإعدادات. هناك حاجة إلى كائن واحد لكل قسم، وكائن آخر مطلوب للإعدادات العامة أعلى الملف.

نظرًا لأن الملف يحتاج إلى تحليل سطرًا تلو الآخر، فمن الجيد أن تبدأ بتقسيم الملف إلى أسطر. للقيام بذلك، استخدمنا string.split("\n") في الفصل السادس. لا تستخدم بعض أنظمة التشغيل حرف \n واحد لفواصل الأسطر، بل تستخدم حرفين - \r\n. بما أن طريقة التقسيم تأخذ التعبيرات العادية كوسيطة، فيمكننا تقسيم الخطوط باستخدام التعبير /\r?\n/، مما يسمح لكل من \n و\r\n الفردي بين الأسطر.

الدالة parseINI(string) ( // لنبدأ بكائن يحتوي على إعدادات المستوى الأعلى var currentSection = (name: null, fields: ); var Categories = ; string.split(/\r?\n/).forEach(function (line ) ( var match; if (/^\s*(;.*)?$/.test(line)) ( return; ) else if (match = line.match(/^\[(.*)\ ]$ /)) ( currentSection = (name: match, fields: ); Categories.push(currentSection); ) else if (match = line.match(/^(\w+)=(.*)$/)) ( currentSection.fields.push((name: match, value: match)); else ( throw new Error("السطر "" + line + "" يحتوي على بيانات غير صالحة."); ) ));

يمر الكود عبر جميع الأسطر، ويحدث كائن القسم الحالي "القسم الحالي". أولاً، يتحقق ما إذا كان يمكن تجاهل السطر باستخدام التعبير العادي /^\s*(;.*)?$/. هل يمكنك أن تتخيل كيف يعمل هذا؟ الجزء الموجود بين القوسين يطابق التعليقات، أليس كذلك؟ يجعل الحرف العادي يتطابق أيضًا مع الأسطر التي تتكون من مسافات فقط.

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

الاحتمال الأخير ذو المعنى هو أن السلسلة هي إعداد عادي، وفي هذه الحالة تتم إضافتها إلى الكائن الحالي.

إذا لم يعمل أي من الخيارات، فستؤدي الوظيفة إلى ظهور خطأ.

لاحظ كيف أن الاستخدام المتكرر لـ ^ و$ يضمن أن التعبير يطابق السلسلة بأكملها بدلاً من جزء منها فقط. إذا لم تستخدمها، فستعمل التعليمات البرمجية بشكل عام، ولكنها قد تؤدي في بعض الأحيان إلى نتائج غريبة وسيكون من الصعب تعقب الخطأ.

إن بناء if (match = string.match(...)) يشبه خدعة استخدام المهمة كشرط في حلقة while. في كثير من الأحيان لا تعرف أن استدعاء المطابقة سينجح، لذا يمكنك فقط الوصول إلى الكائن الناتج داخل كتلة if التي تتحقق منه. لكي لا نكسر السلسلة الجميلة من عمليات التحقق، نقوم بتعيين نتيجة البحث لمتغير واستخدام هذا التعيين على الفور كفحص.

الرموز الدولية

نظرًا للتنفيذ البسيط للغة في البداية، والتثبيت اللاحق لمثل هذا التنفيذ "بالجرانيت"، فإن تعبيرات JavaScript العادية تكون غبية مع الأحرف غير الموجودة في اللغة الإنجليزية. على سبيل المثال، يمكن أن يكون حرف "الحرف"، من وجهة نظر تعبيرات JavaScript العادية، أحد الحروف الـ 26 للأبجدية الإنجليزية، ولسبب ما أيضًا شرطة سفلية. الحروف مثل é أو β، والتي من الواضح أنها أحرف، لا تتطابق مع \w (وسوف تتطابق مع \W، وهو غير حرف).

في تطور غريب، تاريخيًا \s (مسافة) تتطابق مع جميع الأحرف التي تعتبر مسافة بيضاء في Unicode، بما في ذلك أشياء مثل المسافة غير المنفصلة أو فاصل حرف العلة المنغولي.

تحتوي بعض تطبيقات regex في اللغات الأخرى على بنية خاصة للبحث عن فئات خاصة من أحرف Unicode، مثل "جميع الأحرف الكبيرة" أو "جميع علامات الترقيم" أو "أحرف التحكم". هناك خطط لإضافة مثل هذه الفئات إلى JavaScript، ولكن من المحتمل ألا يتم تنفيذها قريبًا.

الحد الأدنى

العناصر النظامية هي كائنات تمثل أنماط البحث في السلاسل. يستخدمون بناء الجملة الخاص بهم للتعبير عن هذه الأنماط.

/ اي بي سي / تسلسل الأحرف
// أي حرف من القائمة
/[^abc]/ أي حرف باستثناء الأحرف الموجودة في القائمة
// أي حرف من الفاصل الزمني
/x+/ تكرار واحد أو أكثر للنمط x
/x+?/ حدث واحد أو أكثر، غير جشع
/x*/ صفر أو أكثر
/x?/ صفر أو حدث واحد
/x(2,4)/ من مرتين إلى أربع مرات
/(اي بي سي)/ المجموعة
/a|b|c/ أي من الأنماط المتعددة
/\د/ أي رقم
/\w/ أي حرف أبجدي رقمي ("حرف")
/\s/ أي حرف مسافة بيضاء
/./ أي حرف باستثناء فواصل الأسطر
/\b/ حد الكلمة
/^/ بداية السطر
/$/ نهاية السطر

يحتوي التعبير العادي على طريقة اختبار للتحقق مما إذا كان النمط موجودًا في السلسلة. توجد طريقة exec تُرجع مصفوفة تحتوي على جميع المجموعات الموجودة. يحتوي المصفوفة على خاصية فهرس، والتي تحتوي على رقم الحرف الذي حدثت منه المطابقة.

تحتوي السلاسل على طريقة مطابقة لمطابقة الأنماط، وطريقة بحث تقوم بإرجاع موضع البداية للحدث فقط. يمكن للأسلوب استبدال استبدال تكرارات النمط بسلسلة أخرى. بالإضافة إلى ذلك، يمكنك تمرير وظيفة للاستبدال والتي ستنشئ سطرًا بديلًا استنادًا إلى القالب والمجموعات التي تم العثور عليها.

تحتوي الأحرف العادية على إعدادات مكتوبة بعد الشرطة المائلة للإغلاق. يجعل الخيار i التعبير العادي غير حساس لحالة الأحرف، والخيار g يجعله عموميًا، مما يؤدي، من بين أمور أخرى، إلى استبدال طريقة الاستبدال لجميع التكرارات التي تم العثور عليها، وليس فقط التكرار الأول.

يمكن استخدام مُنشئ RegExp لإنشاء تعبيرات عادية من السلاسل.

المنظمون أداة حادة ذات مقبض غير مريح. إنها تبسط بعض المهام إلى حد كبير، ويمكن أن تصبح غير قابلة للإدارة عند حل المشكلات المعقدة الأخرى. جزء من تعلم استخدام التعابير المنطقية هو القدرة على مقاومة إغراء إغراقهم بمهمة غير مخصصة لهم.

تمارين

حتمًا عند حل المشكلات، ستواجه حالات غير مفهومة، وقد تشعر باليأس أحيانًا عندما ترى السلوك غير المتوقع لبعض التعبيرات العادية. في بعض الأحيان يكون من المفيد دراسة سلوك محرك عادي من خلال خدمة عبر الإنترنت مثل debuggex.com، حيث يمكنك رؤية تصوره ومقارنته بالتأثير المطلوب.
الجولف العادي
"الجولف" في الكود هي لعبة تحتاج فيها إلى التعبير عن برنامج معين بأقل عدد من الأحرف. الجولف العادي هو تمرين عملي في كتابة أصغر اللاعبين المنتظمين الممكنين للعثور على نمط معين، وهذا فقط.

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

السيارة والقطة
- البوب ​​والدعامة
- النمس والعبارة والفيراري
- أي كلمة تنتهي بـ ious
- مسافة تليها نقطة أو فاصلة أو نقطتين أو فاصلة منقوطة.
- كلمة أطول من ستة أحرف
- كلمة بدون حروف ه

// أدخل التعبيرات النمطية الخاصة بك check(/.../, ["my car", "bad cats"], ["camper", "high art"]); تحقق(/.../, ["ثقافة البوب"، "الدعائم المجنونة"]، ["plop"]); check(/.../, ["ferret"، "ferry"، "ferrari"]، ["ferrum"، "transfer A"]); تحقق(/.../, ["كم هو لذيذ"، "غرفة واسعة"]، ["مدمر"، "الوعي"]); تحقق(/.../, ["علامات الترقيم سيئة."], ["الهروب من النقطة"]); تحقق(/.../, ["hottenottententen"], ["no", "hotten tottententen"]); تحقق(/.../, ["خلد الماء الأحمر"، "العش المتذبذب"]، ["سرير الأرض"، "قرد التعلم"]); التحقق من الوظيفة (regexp, Yes, no) ( // تجاهل التمارين غير المكتملة if (regexp.source == "...") return; Yes.forEach(function(s) ( if (!regexp.test(s)) console .log("لم يتم العثور على "" + s + """ )); no.forEach(function(s) ( if (regexp.test(s)) console.log("حدث غير متوقع "" + s + " "" ));

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

ابتكر نمطًا يميز بين هذين الاستخدامين لعلامات الاقتباس، واكتب استدعاءً للتابع استبدال الذي يقوم بالاستبدال.

الأرقام مرة أخرى
يمكن العثور على تسلسل الأرقام باستخدام تعبير عادي بسيط /\d+/.

اكتب تعبيرًا يبحث فقط عن الأرقام المكتوبة بأسلوب JavaScript. يجب أن يدعم علامة ناقص أو علامة زائد محتملة قبل الرقم والفاصلة العشرية والترميز العلمي 5e-3 أو 1E10 - مرة أخرى مع علامة زائد أو ناقص محتملة. لاحظ أيضًا أنه قد لا تكون هناك بالضرورة أرقام قبل النقطة أو بعدها، ولكن لا يمكن أن يتكون الرقم من نقطة واحدة. أي أن .5 أو 5. هي أرقام صالحة، لكن النقطة الواحدة في حد ذاتها ليست كذلك.

// أدخل التسلسل العادي هنا. رقم فار = /^...$/; // الاختبارات: ["1"، "-1"، "+15"، "1.55"، ".5"، "5."، "1.3e2"، "1E-4"، "1e+12"] .forEach(function(s) ( if (!number.test(s)) console.log("لم يتم العثور على "" + s + """); )); ["1a"، "+-1"، "1.2.3"، "1+1"، "1e4.5"، ".5."، "1f5"، "."].forEach(function(s) ( if (number.test(s)) console.log("تم قبوله بشكل غير صحيح "" + s + """); ));

بعض الأشخاص، عندما يواجهون مشكلة ما، يفكرون: "أوه، سأستخدم التعبيرات العادية." الآن لديهم مشكلتين.
جيمي زاوينسكي

قال يوان ما، "إن قطع الخشب عبر حبيبات الخشب يتطلب الكثير من القوة. يستغرق الأمر الكثير من التعليمات البرمجية للبرمجة عبر بنية المشكلة.
المعلم يوان ما، "كتاب البرمجة"

أدوات وتقنيات البرمجة تبقى على قيد الحياة وتنتشر بطريقة تطورية فوضوية. في بعض الأحيان، لا يبقى الأشخاص الجميلون والرائعون، ولكن ببساطة أولئك الذين يعملون بشكل جيد بما فيه الكفاية في مجالهم - على سبيل المثال، إذا تم دمجهم في تقنية أخرى ناجحة.

في هذا الفصل، سنناقش مثل هذه الأداة - التعبيرات العادية. هذه طريقة لوصف الأنماط في بيانات السلسلة. يقومون بإنشاء لغة صغيرة مستقلة مضمنة في JavaScript والعديد من اللغات والأدوات الأخرى.

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

إنشاء تعبير عادي

عادي - نوع الكائن. يمكن إنشاؤه عن طريق استدعاء مُنشئ RegExp، أو عن طريق كتابة القالب المطلوب، محاطًا بخطوط مائلة.

var re1 = new RegExp("abc"); فار re2 = /abc/;

يمثل كلا التعبيرين النمطيين نفس النمط: الحرف "a" متبوعًا بالحرف "b" متبوعًا بالحرف "c".

إذا كنت تستخدم منشئ RegExp، فسيتم كتابة النمط كسلسلة عادية، لذلك يتم تطبيق جميع القواعد المتعلقة بالخطوط المائلة العكسية.

الإدخال الثاني، حيث يكون النمط بين الخطوط المائلة، يعامل الخطوط المائلة العكسية بشكل مختلف. أولاً، نظرًا لأن النمط ينتهي بشرطة مائلة للأمام، فنحن بحاجة إلى وضع شرطة مائلة للخلف قبل الشرطة المائلة للأمام التي نريد تضمينها في نمطنا. بالإضافة إلى ذلك، سيتم الحفاظ على الخطوط المائلة العكسية التي لا تشكل جزءًا من أحرف خاصة مثل \n (بدلاً من تجاهلها كما هو الحال في السلاسل)، وسوف تغير معنى النمط. بعض الأحرف، مثل علامة الاستفهام أو علامة الزائد، لها معنى خاص في التعبيرات العادية، وإذا كنت بحاجة إلى العثور على مثل هذا الحرف، فيجب أيضًا أن يسبقه شرطة مائلة عكسية.

var EighteenPlus = /ثمانية عشر\+/;

لمعرفة الأحرف التي يجب أن تسبقها شرطة مائلة، يتعين عليك التعرف على قائمة بجميع الأحرف الخاصة في التعبيرات العادية. هذا غير ممكن حتى الآن، لذلك عندما تكون في شك، ما عليك سوى وضع شرطة مائلة عكسية أمام أي حرف ليس حرفًا أو رقمًا أو مسافة.

التحقق من وجود مباريات

النظاميون لديهم عدة طرق. أبسط واحد هو الاختبار. إذا قمت بتمرير سلسلة، فسوف تُرجع قيمة منطقية تشير إلى ما إذا كانت السلسلة تحتوي على تكرار للنمط المحدد.

Console.log(/abc/.test("abcde")); // → صحيح console.log(/abc/.test("abxde")); // → خطأ

التسلسل العادي الذي يتكون فقط من أحرف غير خاصة هو ببساطة تسلسل من هذه الأحرف. إذا كان abc في أي مكان في السطر الذي نختبره (وليس فقط في البداية)، فسيعود الاختبار صحيحًا.

أبحث عن مجموعة من الشخصيات

يمكنك أيضًا معرفة ما إذا كانت السلسلة تحتوي على abc باستخدام ملف IndexOf. تتيح لك الأنماط العادية المضي قدمًا وإنشاء أنماط أكثر تعقيدًا.

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

كلا التعبيرين موجودان في أسطر تحتوي على رقم.

Console.log(//.test("في عام 1992")); // → صحيح console.log(//.test("في 1992")); // → صحيح

بين قوسين مربعين، يتم استخدام شرطة بين حرفين لتحديد نطاق من الأحرف، حيث يتم تحديد التسلسل بواسطة ترميز Unicode. الأحرف من 0 إلى 9 موجودة في صف واحد فقط (الرموز من 48 إلى 57)، لذا فهي تلتقطها جميعًا وتطابق أي رقم.

تحتوي العديد من مجموعات الأحرف على اختصارات مدمجة خاصة بها.

\d أي رقم
\w حرف أبجدي رقمي
\s حرف المسافة البيضاء (مسافة، علامة تبويب، سطر جديد، إلخ.)
\D ليس رقما
\W ليس حرفًا أبجديًا رقميًا
\S ليس حرف مسافة بيضاء
. أي حرف باستثناء تغذية السطر

وبالتالي، يمكنك ضبط تنسيق التاريخ والوقت مثل 30/01/2003 15:20 بالتعبير التالي:

var dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/; console.log(dateTime.test("30-01-2003 15:20")); // → صحيح console.log(dateTime.test("30 يناير 2003 15:20")); // → خطأ

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

يمكن أيضًا استخدام الخطوط المائلة العكسية بين قوسين مربعين. على سبيل المثال، [\d.] يعني أي رقم أو فترة. لاحظ أن النقطة الموجودة داخل الأقواس المربعة تفقد معناها الخاص وتصبح مجرد نقطة. وينطبق الشيء نفسه على الأحرف الخاصة الأخرى، مثل +.

يمكنك عكس مجموعة من الأحرف - أي أنك تحتاج إلى العثور على أي حرف باستثناء تلك الموجودة في المجموعة - عن طريق وضع علامة ^ مباشرة بعد قوس الفتح المربع.

var notBinary = /[^01]/; console.log(notBinary.test("1100100010100110")); // → false console.log(notBinary.test("1100100010200110")); // → صحيح

تكرار أجزاء من القالب

نحن نعرف كيفية العثور على رقم واحد. ماذا لو أردنا إيجاد العدد الصحيح - سلسلة مكونة من رقم واحد أو أكثر؟

إذا وضعت علامة + بعد شيء ما في التسلسل المنتظم، فهذا يعني أنه يمكن تكرار هذا العنصر أكثر من مرة. /\d+/ يعني رقمًا واحدًا أو أكثر.

Console.log(/"\d+"/.test(""123"")); // → صحيح console.log(/"\d+"/.test("""")); // → false console.log(/"\d*"/.test(""123"")); // → صحيح console.log(/"\d*"/.test("""")); // → صحيح

العلامة النجمية * لها نفس المعنى تقريبًا، ولكنها تسمح بتكرار النمط صفر مرة. إذا كان هناك شيء متبوع بعلامة النجمة، فهذا يعني عدم منع النمط من التواجد في السطر - فهو يظهر هناك صفر مرة.

علامة الاستفهام تجعل جزءًا من النموذج اختياريًا، مما يعني أنه يمكن أن يحدث صفرًا أو مرة واحدة. في المثال التالي، قد يظهر الحرف u، لكن النمط يتطابق حتى عندما لا يظهر.

فار الجار = /neighbou?r/; console.log(neighbor.test("neighbor")); // → صحيح console.log(neighbor.test("neighbor")); // → صحيح

يتم استخدام الأقواس المتعرجة لتحديد العدد الدقيق للمرات التي يجب أن يحدث فيها النمط. (4) بعد العنصر يعني أنه يجب أن يظهر 4 مرات في السطر. يمكنك أيضًا تحديد فجوة: (2،4) تعني أن العنصر يجب أن يتكرر مرتين على الأقل ولا يزيد عن 4 مرات.

نسخة أخرى من تنسيق التاريخ والوقت، حيث يُسمح بالأيام والأشهر والساعات المكونة من رقم واحد أو رقمين. كما أنها أكثر قابلية للقراءة قليلاً.

var dateTime = /\d(1,2)-\d(1,2)-\d(4) \d(1,2):\d(2)/; console.log(dateTime.test("30-1-2003 8:45")); // → صحيح

يمكنك استخدام المساحات المفتوحة عن طريق حذف أحد الأرقام. (،5،) تعني أن النمط يمكن أن يحدث من صفر إلى خمس مرات، و(5،) تعني من خمس مرات أو أكثر.

تجميع التعبيرات الفرعية

لاستخدام عوامل التشغيل * أو + على عناصر متعددة في وقت واحد، يمكنك استخدام الأقواس. يعتبر جزء التعبير النمطي الموجود بين قوسين عنصرًا واحدًا من وجهة نظر المشغلين.

var CartoonCrying = /boo+(hoo+)+/i; console.log(cartoonCrying.test("Boohoooohoohooo")); // → صحيح

الزائد الأول والثاني ينطبق فقط على الثاني o في الكلمتين boo وhoo. الثالث + يشير إلى المجموعة بأكملها (hoo+)، ويجد واحدًا أو أكثر من هذه التسلسلات.

الحرف i الموجود في نهاية التعبير يجعل التعبير العادي غير حساس لحالة الأحرف - بحيث يتطابق B مع b.

المباريات والمجموعات

طريقة الاختبار هي أبسط طريقة للتحقق من التعبيرات العادية. يخبرك فقط ما إذا تم العثور على تطابق أم لا. لدى العناصر النظامية أيضًا طريقة exec، والتي ستعيد القيمة null إذا لم يتم العثور على أي شيء، وتعيد كائنًا يحتوي على معلومات حول المطابقة.

var match = /\d+/.exec("واحد اثنان 100"); console.log(match); // → ["100"] console.log(match.index); // → 8

يحتوي الكائن الذي تم إرجاعه بواسطة exec على خاصية فهرس، والتي تحتوي على رقم الحرف الذي حدثت منه المطابقة. بشكل عام، يبدو الكائن كمصفوفة من السلاسل، حيث يكون العنصر الأول هو السلسلة التي تم التحقق من تطابقها. في مثالنا، سيكون هذا هو تسلسل الأرقام الذي كنا نبحث عنه.

السلاسل لها طريقة مطابقة تعمل بنفس الطريقة تقريبًا.

Console.log("واحد اثنان 100".match(/\d+/)); // → ["100"]

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

var quoteText = /"([^"]*)"/; console.log(quotedText.exec("قالت "hello"")); // → [""hello"", "hello"]

عندما لا يتم العثور على مجموعة على الإطلاق (على سبيل المثال، إذا كانت متبوعة بعلامة استفهام)، يكون موضعها في المصفوفة غير محدد. إذا تطابقت المجموعة عدة مرات، فستكون المباراة الأخيرة فقط في المصفوفة.

Console.log(/bad(ly)?/.exec("bad")); // → ["سيء"، غير محدد] console.log(/(\d)+/.exec("123")); // → ["123"، "3"]

المجموعات مفيدة لاسترداد أجزاء من السلاسل. إذا لم نكن نريد فقط التحقق مما إذا كانت السلسلة تحتوي على تاريخ، ولكننا نستخرجها وننشئ كائنًا يمثل التاريخ، فيمكننا وضع تسلسل الأرقام بين قوسين واختيار التاريخ من نتيجة exec.

لكن أولاً، القليل من الاستطراد الذي سنتعلم فيه الطريقة المفضلة لتخزين التاريخ والوقت في JavaScript.

نوع التاريخ

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

Console.log(new Date()); // → الأحد 09 نوفمبر 2014 00:07:57 بتوقيت جرينتش+0300 (توقيت وسط أوروبا)

يمكنك أيضًا إنشاء كائن يحتوي على وقت معين

Console.log(new Date(2015, 9, 21)); // → الأربعاء 21 أكتوبر 2015 00:00:00 بتوقيت جرينتش+0300 (CET) console.log(new Date(2009, 11, 9, 12, 59, 59, 999)); // → الأربعاء 09 ديسمبر 2009 12:59:59 بتوقيت جرينتش+0300 (توقيت وسط أوروبا)

تستخدم JavaScript تقليدًا حيث تبدأ أرقام الأشهر بصفر وتبدأ أرقام اليوم بواحد. هذا غبي ومثير للسخرية. احترس.

تعتبر الوسيطات الأربع الأخيرة (الساعات والدقائق والثواني والميلي ثانية) اختيارية ويتم ضبطها على صفر في حالة فقدانها.

يتم تخزين الطوابع الزمنية على هيئة عدد المللي ثانية التي مرت منذ بداية عام 1970. في الأوقات التي سبقت عام 1970، تم استخدام الأرقام السالبة (وهذا بسبب اصطلاح وقت Unix الذي تم إنشاؤه في ذلك الوقت تقريبًا). تقوم طريقة getTime الخاصة بكائن التاريخ بإرجاع هذا الرقم. إنها كبيرة بشكل طبيعي.
console.log(new Date(2013, 11, 19).getTime()); // → 1387407600000 console.log(new Date(1387407600000)); // → الخميس 19 ديسمبر 2013 00:00:00 بتوقيت جرينتش+0100 (توقيت وسط أوروبا)

إذا أعطيت مُنشئ التاريخ وسيطة واحدة، فسيتم التعامل معها على هذا العدد من المللي ثانية. يمكنك الحصول على قيمة المللي ثانية الحالية عن طريق إنشاء كائن Date واستدعاء الأسلوب getTime، أو عن طريق استدعاء الدالة Date.now.

يحتوي كائن التاريخ على أساليب getFullYear، وgetMonth، وgetDate، وgetHours، وgetMinutes، وgetSeconds لاسترداد مكوناته. هناك أيضًا طريقة getYear التي تُرجع رمزًا مكونًا من رقمين عديم الفائدة مثل 93 أو 14.

من خلال وضع الأجزاء ذات الصلة من القالب بين قوسين، يمكننا إنشاء كائن تاريخ مباشرة من السلسلة.

دالة findDate(string) ( var dateTime = /(\d(1,2))-(\d(1,2))-(\d(4))/; var match = dateTime.exec(string); return تاريخ جديد (رقم (تطابق)، رقم (تطابق) - 1، رقم (تطابق) ) console.log(findDate("30-1-2003")); // → الخميس 30 يناير 2003 00:00:00 بتوقيت جرينتش+0100 (توقيت وسط أوروبا)

حدود الكلمة والخط

لسوء الحظ، سيتمكن findDate من استخراج التاريخ الذي لا معنى له 00-1-3000 من السلسلة "100-1-30000". يمكن أن تحدث المطابقة في أي مكان في السلسلة، لذلك في هذه الحالة ستبدأ ببساطة عند الحرف الثاني وتنتهي عند الحرف الثاني قبل الأخير.

إذا أردنا فرض المطابقة على السلسلة بأكملها، فإننا نستخدم علامتي ^ و$. ^ يطابق بداية السطر، و $ يطابق النهاية. لذلك، /^\d+$/ يطابق سلسلة تحتوي على رقم واحد فقط أو أكثر، /^!/ يطابق سلسلة تبدأ بعلامة تعجب، و /x^/ لا يطابق أي سلسلة (لا يمكن أن يكون هناك x).

من ناحية أخرى، إذا أردنا فقط التأكد من أن التاريخ يبدأ وينتهي عند حد الكلمة، فإننا نستخدم العلامة \b. يمكن أن يكون حد الكلمة هو بداية السطر أو نهايته، أو أي مكان في السطر حيث يوجد حرف أبجدي رقمي \w على أحد الجانبين وحرف غير أبجدي رقمي على الجانب الآخر.

Console.log(/cat/.test("تسلسل")); // → صحيح console.log(/\bcat\b/.test("concatenate")); // → خطأ

لاحظ أن تسمية الحدود ليست رمزًا. إنه ببساطة قيد يعني أن التطابق يحدث فقط في حالة استيفاء شرط معين.

قوالب مع الاختيار

لنفترض أنك بحاجة إلى معرفة ما إذا كان النص لا يحتوي على رقم فقط، بل يحتوي على رقم متبوعًا بخنزير أو بقرة أو دجاج بصيغة المفرد أو الجمع.

سيكون من الممكن كتابة ثلاثة تعبيرات عادية والتحقق منها واحدة تلو الأخرى، ولكن هناك طريقة أفضل. الرمز | يشير إلى الاختيار بين الأنماط الموجودة على يساره وعلى يمينه. ويمكننا أن نقول ما يلي:

var AnimalCount = /\b\d+ (خنزير|بقرة|دجاج)s?\b/; console.log(animalCount.test("15 خنزير")); // → صحيح console.log(animalCount.test("15 دجاج خنزير")); // → خطأ

تحدد الأقواس جزء النموذج الذي يتم تطبيق | عليه، ويمكن وضع العديد من عوامل التشغيل واحدًا تلو الآخر للإشارة إلى الاختيار من بين أكثر من خيارين.

محرك البحث

يمكن اعتبار التعبيرات العادية بمثابة مخططات انسيابية. ويصف الرسم البياني التالي مثالا حديثا للماشية.

يتطابق التعبير مع سلسلة إذا كان من الممكن العثور على مسار من الجانب الأيسر من الرسم التخطيطي إلى اليمين. نتذكر الموضع الحالي في السطر، وفي كل مرة نمر عبر المستطيل، نتحقق من أن جزء الخط الذي يلي موضعنا فيه مباشرة يطابق محتويات المستطيل.

هذا يعني أن التحقق من تطابق حرفنا العادي في السلسلة "الخنازير الثلاثة" عند المرور عبر المخطط الانسيابي يبدو كما يلي:

في الموضع 4 يوجد حد للكلمة، ونمرر المستطيل الأول
- بدءًا من الموضع الرابع نجد الرقم ونمر عبر المستطيل الثاني
- في الموضع 5، يُغلق أحد المسارين أمام المستطيل الثاني، ويتجه الثاني إلى المستطيل بمسافة. لدينا مساحة وليس رقمًا، ونختار المسار الثاني.
- الآن نحن في الموضع 6، بداية "الخنازير"، وعند التفرع الثلاثي للمسارات. ليس هناك "بقرة" أو "دجاجة" في الخط، ولكن هناك "خنزير"، لذلك اخترنا هذا المسار.
- في الموضع 9 بعد الشوكة الثلاثية، يتجاوز المسار "s" ويذهب إلى مستطيل حد الكلمة الأخيرة، ويمر الثاني عبر "s". لدينا حرف "s" لذا نذهب إلى هناك.
- في الموضع 10 نحن في نهاية السطر، ولا يمكن أن يتطابق إلا مع حد الكلمة. نهاية الخط تعتبر الحد، ونمر بالمستطيل الأخير. والآن نجحنا في العثور على القالب الخاص بنا.

في الأساس، الطريقة التي تعمل بها التعبيرات العادية هي أن الخوارزمية تبدأ في بداية السلسلة وتحاول العثور على تطابق هناك. في حالتنا، هناك حد للكلمة، فتتجاوز المستطيل الأول - لكن لا يوجد رقم هناك، فتتعثر في المستطيل الثاني. ثم ينتقل إلى الحرف الثاني في السلسلة، ويحاول العثور على تطابق هناك... وهكذا حتى يجد تطابقًا أو يصل إلى نهاية السلسلة، وفي هذه الحالة لا يتم العثور على تطابق.

العمولات

التعبير العادي /\b(+b|\d+|[\da-f]h)\b/ يطابق إما رقمًا ثنائيًا متبوعًا بـ b، أو رقمًا عشريًا بدون لاحقة، أو رقمًا سداسيًا عشريًا (الأرقام من 0 إلى 9) أو الرموز من a إلى h)، متبوعة بـ h. الرسم البياني ذو الصلة:

عند البحث عن تطابق، قد يحدث أن تأخذ الخوارزمية المسار العلوي (الرقم الثنائي)، حتى لو لم يكن هناك رقم كهذا في السلسلة. إذا كان هناك سطر "103"، على سبيل المثال، فمن الواضح أنه فقط بعد الوصول إلى الرقم 3 ستدرك الخوارزمية أنه على المسار الخاطئ. بشكل عام، السطر يطابق التسلسل العادي، ولكن ليس في هذا الموضوع.

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

تتوقف الخوارزمية بمجرد العثور على تطابق كامل. وهذا يعني أنه حتى لو كانت هناك عدة خيارات مناسبة، فسيتم استخدام واحد منها فقط (بالترتيب الذي تظهر به في التسلسل العادي).

يحدث التراجع عند استخدام عوامل التكرار مثل + و*. إذا بحثت عن /^.*x/ في السلسلة "abcxe"، فسيحاول جزء regex.* استهلاك السلسلة بأكملها. ستدرك الخوارزمية بعد ذلك أنها تحتاج أيضًا إلى "x". نظرًا لعدم وجود "x" بعد نهاية السلسلة، ستحاول الخوارزمية البحث عن تطابق من خلال إرجاع حرف واحد للخلف. بعد abcx أيضًا لا يوجد x، ثم يتراجع مرة أخرى، هذه المرة إلى السلسلة الفرعية abc. وبعد السطر، يجد x ويبلغ عن تطابق ناجح، في المواضع من 0 إلى 4.

يمكنك كتابة روتين منتظم يؤدي إلى تراجعات متعددة. تحدث هذه المشكلة عندما يتطابق النمط مع الإدخال بعدة طرق مختلفة. على سبيل المثال، إذا ارتكبنا خطأً عند كتابة التعبير العادي للأرقام الثنائية، فقد نكتب عن طريق الخطأ شيئًا مثل /(+)+b/.

إذا كانت الخوارزمية تبحث عن مثل هذا النمط في سلسلة طويلة من 0 و1 لا تحتوي على "b" في النهاية، فسوف تمر أولاً عبر الحلقة الداخلية حتى نفاد الأرقام. ثم سيلاحظ أنه لا يوجد "ب" في النهاية، وسوف يتراجع عن موضع واحد، ويمر عبر الحلقة الخارجية، ويستسلم مرة أخرى، ويحاول العودة إلى موضع آخر على طول الحلقة الداخلية... وسيستمر للبحث بهذه الطريقة باستخدام كلا الحلقتين. أي أن مقدار العمل مع كل حرف في السطر سوف يتضاعف. حتى بالنسبة لعشرات الشخصيات، سيستغرق العثور على تطابق وقتًا طويلاً جدًا.

استبدال الطريقة

تحتوي السلاسل على طريقة استبدال يمكنها استبدال جزء من سلسلة بسلسلة أخرى.

Console.log("dad".replace("p", "m")); // → الخريطة

يمكن أن تكون الوسيطة الأولى أيضًا تعبيرًا عاديًا، وفي هذه الحالة يتم استبدال التواجد الأول للتعبير العادي في السطر. عند إضافة الخيار "g" (العالمي) إلى تعبير عادي، يتم استبدال جميع التكرارات، وليس الأول فقط

Console.log("Borobudur".replace(//, "a")); // → باروبودور console.log("Borobudur".replace(//g, "a")); // → بارادار

سيكون من المنطقي تمرير خيار "استبدال الكل" من خلال وسيطة منفصلة، ​​أو من خلال طريقة منفصلة مثل استبدال الكل. لكن للأسف ينتقل الخيار عبر النظام العادي نفسه.

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

Console.log("هوبر، جريس\nمكارثي، جون\nريتشي، دينيس" .replace(/([\w ]+), ([\w ]+)/g, "$2 $1")); // → غريس هوبر // جون مكارثي // دينيس ريتشي

يشير $1 و$2 في سطر الاستبدال إلى مجموعات من الأحرف المحاطة بين قوسين. يتم استبدال $1 بالنص الذي يطابق المجموعة الأولى، و$2 بالمجموعة الثانية، وهكذا حتى 9 $. المطابقة بأكملها موجودة في المتغير $&.

يمكنك أيضًا تمرير دالة باعتبارها الوسيطة الثانية. لكل استبدال، سيتم استدعاء دالة ستكون وسيطاتها هي المجموعات التي تم العثور عليها (والجزء المطابق بالكامل من السلسلة)، وسيتم إدراج نتيجتها في سطر جديد.

مثال بسيط:

var s = "وكالة المخابرات المركزية ومكتب التحقيقات الفيدرالي"; console.log(s.replace(/\b(fbi|cia)\b/g, function(str) ( return str.toUpperCase(); ))); // → وكالة المخابرات المركزية ومكتب التحقيقات الفيدرالي

إليك واحدة أكثر إثارة للاهتمام:

مخزون فار = "1 ليمونة، 2 ملفوف، و101 بيضة"؛ دالة minusOne(match, المبلغ, الوحدة) ( المبلغ = الرقم(المبلغ) - 1; إذا (المبلغ == 1) // بقي واحد فقط، قم بإزالة "s" في النهاية Unit =unit.slice(0,unit. الطول - 1)؛ وإلا إذا (المبلغ == 0) المبلغ = "لا"؛ مبلغ الإرجاع + "" + الوحدة) console.log(stock.replace(/(\d+) (\w+)/g, minusOne) ); // → بدون ليمون، 1 ملفوف، و100 بيضة

يأخذ الكود سلسلة، ويبحث عن جميع تكرارات الأرقام متبوعة بكلمة، ويعيد سلسلة مع تقليل كل رقم بمقدار واحد.

تنتقل المجموعة (\d+) إلى وسيطة المبلغ، وتنتقل (\w+) إلى وسيطة الوحدة. تقوم الدالة بتحويل المبلغ إلى رقم - وهذا يعمل دائمًا، لأن النمط الخاص بنا هو \d+. ثم يقوم بإجراء تغييرات على الكلمة، في حالة وجود عنصر واحد فقط متبقي.

جشع

من السهل استخدام الاستبدال لكتابة دالة تزيل جميع التعليقات من كود JavaScript. ها هي المحاولة الأولى:

الدالة stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*\*\//g, ""); ) console.log(stripComments("1 + /* 2 */3")); // → 1 + 3 console.log(stripComments("x = 10;// عشرة!")); // → س = 10؛ console.log(stripComments("1 /* أ */+/* ب */ 1")); // → 1 1

يتطابق الجزء الموجود قبل عامل التشغيل "أو" مع شرطتين متبوعتين بأي عدد من الأحرف باستثناء الأسطر الجديدة. الجزء الذي يزيل التعليقات متعددة الأسطر أكثر تعقيدًا. نستخدم [^]، أي. أي حرف غير فارغ كوسيلة للعثور على أي حرف. لا يمكننا استخدام نقطة لأن التعليقات المحظورة تستمر في سطر جديد، ولا يتطابق حرف السطر الجديد مع النقطة.

لكن إخراج المثال السابق غير صحيح. لماذا؟

سيحاول الجزء [^]* أولاً التقاط أكبر عدد ممكن من الأحرف. إذا لم يجد الجزء التالي من التسلسل العادي تطابقًا لهذا السبب، فسوف يتراجع حرفًا واحدًا ويحاول مرة أخرى. في المثال، تحاول الخوارزمية الاستيلاء على السطر بأكمله، ثم تتراجع. بعد إرجاع 4 أحرف، سيجد */ في السطر - وهذا ليس ما أردناه. أردنا الحصول على تعليق واحد فقط، وعدم الذهاب إلى نهاية السطر والعثور على التعليق الأخير.

ولهذا السبب، نقول إن عوامل التكرار (+، *، ?، و ()) جشعة، مما يعني أنها تستحوذ أولاً على أكبر قدر ممكن من المعلومات ثم تعود مرة أخرى. إذا وضعت سؤالاً بعد عامل مثل هذا (+?، *?، ??، ()؟)، فسوف يتحول إلى غير جشع، ويبدأ في العثور على أصغر الأحداث الممكنة.

وهذا ما نحتاجه. من خلال إجبار العلامة النجمية على البحث عن التطابقات في أقل عدد ممكن من الأحرف في السطر، فإننا نستهلك كتلة واحدة فقط من التعليقات، وليس أكثر.

الدالة stripComments(code) ( return code.replace(/\/\/.*|\/\*[^]*?\*\//g, ""); ) console.log(stripComments("1 /* أ */+/* ب */ 1")); // → 1 + 1

تحدث العديد من الأخطاء عند استخدام العوامل الجشعة بدلاً من العوامل غير الجشعة. عند استخدام عامل التكرار، فكر دائمًا في خيار المشغل غير الجشع أولاً.

إنشاء كائنات RegExp ديناميكيًا

في بعض الحالات، لا يكون النمط الدقيق معروفًا في وقت كتابة الكود. على سبيل المثال، سوف تحتاج إلى البحث عن اسم المستخدم في النص، وإحاطته بشرطة سفلية. نظرًا لأنك لن تعرف الاسم إلا بعد تشغيل البرنامج، فلا يمكنك استخدام علامة الشرطة المائلة.

ولكن يمكنك إنشاء السلسلة واستخدام مُنشئ RegExp. هنا مثال:

اسم فار = "هاري"; var text = "وهاري لديه ندبة على جبهته."; var regexp = new RegExp("\\b(" + name + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → و _Harry_ لديه ندبة على جبهته.

عند إنشاء حدود الكلمات، علينا استخدام الخطوط المائلة المزدوجة لأننا نكتبها بخط عادي، وليس بتعبير عادي به خطوط مائلة للأمام. تحتوي الوسيطة الثانية لـ RegExp على خيارات للتعبيرات العادية - في حالتنا "gi"، أي. عالمية وغير حساسة لحالة الأحرف.

ولكن ماذا لو كان الاسم "dea+hlrd" (إذا كان مستخدمنا كولهاتزكر)؟ ونتيجة لذلك، سوف نحصل على تعبير عادي لا معنى له ولن يجد تطابقات في السلسلة.

يمكننا إضافة خطوط مائلة عكسية قبل أي شخصية لا نحبها. لا يمكننا إضافة خطوط مائلة عكسية قبل الأحرف لأن \b أو \n أحرف خاصة. ولكن يمكنك إضافة خطوط مائلة قبل أي أحرف غير أبجدية رقمية دون أي مشاكل.

اسم فار = "dea+hlrd"; var text = "هذا dea+hlrd يزعج الجميع."; var escaped = name.replace(/[^\w\s]/g, "\\$&"); var regexp = new RegExp("\\b(" + escaped + ")\\b", "gi"); console.log(text.replace(regexp, "_$1_")); // → هذا _dea+hlrd_ أزعج الجميع.

طريقة البحث

لا يمكن استخدام الأسلوب IndexOf مع التعبيرات العادية. ولكن هناك طريقة بحث تتوقع فقط التعبير العادي. مثل مؤشر IndexOf، فإنه يُرجع فهرس التواجد الأول، أو -1 في حالة عدم حدوث أي شيء.

Console.log("word".search(/\S/)); // → 2 console.log(" ".search(/\S/)); // → -1

لسوء الحظ، لا توجد طريقة لإخبار الطريقة بالبحث عن تطابق بدءًا من إزاحة معينة (كما يمكنك القيام به باستخدام مؤشر IndexOf). سيكون ذلك مفيدًا.

خاصية الفهرس الأخير

لا يوفر التابع exec أيضًا طريقة ملائمة لبدء البحث من موضع معين في السلسلة. لكنه يعطي وسيلة غير مريحة.

كائن regex له خصائص. واحد منهم هو المصدر الذي يحتوي على سلسلة. وهناك خيار آخر هو lastIndex، الذي يتحكم، في بعض الحالات، في المكان الذي سيبدأ فيه البحث التالي عن الأحداث.

تتضمن هذه الشروط أن الخيار العام g يجب أن يكون موجودًا، وأن يتم البحث باستخدام الأسلوب exec. الحل الأكثر منطقية هو السماح ببساطة بتمرير وسيطة إضافية إلى exec، ولكن المعقولية ليست سمة أساسية لواجهة JavaScript regex.

نمط فار = /y/g; style.lastIndex = 3; فار ماتش = Pattern.exec("xyzzy"); console.log(match.index); // → 4 console.log(pattern.lastIndex); // → 5

إذا كان البحث ناجحًا، فسيقوم استدعاء exec بتحديث خاصية lastIndex للإشارة إلى الموضع بعد التكرار الذي تم العثور عليه. إذا لم يكن هناك نجاح، فسيتم تعيين lastIndex على صفر - تمامًا مثل lastIndex للكائن الذي تم إنشاؤه حديثًا.

عند استخدام متغير عادي عام واستدعاءات exec متعددة، يمكن أن تتسبب تحديثات lastIndex التلقائية هذه في حدوث مشكلات. يمكن لخادمك العادي أن يبدأ البحث من الموضع المتبقي من المكالمة السابقة.

رقم فار = /\d/g; console.log(digit.exec("ها هو: 1")); // → ["1"] console.log(digit.exec("والآن: 1")); // → فارغة

تأثير آخر مثير للاهتمام لخيار g هو أنه يغير كيفية عمل طريقة المطابقة. عند استدعائه باستخدام هذا الخيار، بدلاً من إرجاع مصفوفة مشابهة لنتيجة exec، فإنه يبحث عن كافة تكرارات النمط في السلسلة ويعيد مصفوفة من السلاسل الفرعية التي تم العثور عليها.

Console.log("Banana".match(/an/g)); // → ["أن"، "أن"]

لذا كن حذرًا مع المتغيرات العادية العالمية. الحالات التي تكون هناك حاجة إليها - استبدال المكالمات أو الأماكن التي تستخدم فيها lastIndex على وجه التحديد - ربما تكون جميع الحالات التي يجب استخدامها فيها.

دورات الحدوث

تتمثل المهمة النموذجية في تكرار كل تكرارات النمط في سلسلة ما حتى تتمكن من الوصول إلى كائن المطابقة في نص الحلقة باستخدام lastIndex وexec.

var input = "خط به 3 أرقام... 42 و88."; رقم فار = /\b(\d+)\b/g; مباراة فار؛ بينما (match = number.exec(input)) console.log("تم العثور عليه"، تطابق، "on"، match.index)؛ // → تم العثور على 3 في 14 // تم العثور على 42 في 33 // تم العثور على 88 في 40

إنه يستفيد من حقيقة أن قيمة المهمة هي القيمة التي يتم تعيينها. باستخدام match = re.exec(input) كشرط في حلقة while، فإننا نبحث في بداية كل تكرار، ونخزن النتيجة في متغير، وننهي الحلقة عندما يتم العثور على جميع التطابقات.

تحليل ملفات INI

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

Searchengine=http://www.google.com/search?q=$1 النكاية=9.7 ; يتم وضع فاصلة منقوطة قبل التعليقات؛ يشير كل قسم إلى عدو مختلف fullname=نوع Larry Doe=kindergarten Bull website=http://www.geocities.com/CapeCanaveral/11451 fullname=نوع Gargamel=إخراج المعالج الشرير=/home/marijn/enemies/gargamel

تنسيق الملف الدقيق (والذي يستخدم على نطاق واسع، ويسمى عادة INI) هو كما يلي:

يتم تجاهل الأسطر الفارغة والأسطر التي تبدأ بفاصلة منقوطة
- الخطوط المحصورة بين قوسين مربعين تبدأ قسمًا جديدًا
- الأسطر التي تحتوي على معرف أبجدي رقمي متبوعًا بـ = إضافة إعداد في هذا القسم

كل شيء آخر هو بيانات غير صحيحة.

مهمتنا هي تحويل هذه السلسلة إلى مجموعة من الكائنات، لكل منها خاصية اسم ومجموعة من الإعدادات. هناك حاجة إلى كائن واحد لكل قسم، وكائن آخر مطلوب للإعدادات العامة أعلى الملف.

نظرًا لأن الملف يحتاج إلى تحليل سطرًا تلو الآخر، فمن الجيد أن تبدأ بتقسيم الملف إلى أسطر. للقيام بذلك، استخدمنا string.split("\n") في الفصل السادس. لا تستخدم بعض أنظمة التشغيل حرف \n واحد لفواصل الأسطر، بل تستخدم حرفين - \r\n. بما أن طريقة التقسيم تأخذ التعبيرات العادية كوسيطة، فيمكننا تقسيم الخطوط باستخدام التعبير /\r?\n/، مما يسمح لكل من \n و\r\n الفردي بين الأسطر.

الدالة parseINI(string) ( // لنبدأ بكائن يحتوي على إعدادات المستوى الأعلى var currentSection = (name: null, fields: ); var Categories = ; string.split(/\r?\n/).forEach(function (line ) ( var match; if (/^\s*(;.*)?$/.test(line)) ( return; ) else if (match = line.match(/^\[(.*)\ ]$ /)) ( currentSection = (name: match, fields: ); Categories.push(currentSection); ) else if (match = line.match(/^(\w+)=(.*)$/)) ( currentSection.fields.push((name: match, value: match)); else ( throw new Error("السطر "" + line + "" يحتوي على بيانات غير صالحة."); ) ));

يمر الكود عبر جميع الأسطر، ويحدث كائن القسم الحالي "القسم الحالي". أولاً، يتحقق ما إذا كان يمكن تجاهل السطر باستخدام التعبير العادي /^\s*(;.*)?$/. هل يمكنك أن تتخيل كيف يعمل هذا؟ الجزء الموجود بين القوسين يطابق التعليقات، أليس كذلك؟ يجعل الحرف العادي يتطابق أيضًا مع الأسطر التي تتكون من مسافات فقط.

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

الاحتمال الأخير ذو المعنى هو أن السلسلة هي إعداد عادي، وفي هذه الحالة تتم إضافتها إلى الكائن الحالي.

إذا لم يعمل أي من الخيارات، فستؤدي الوظيفة إلى ظهور خطأ.

لاحظ كيف أن الاستخدام المتكرر لـ ^ و$ يضمن أن التعبير يطابق السلسلة بأكملها بدلاً من جزء منها فقط. إذا لم تستخدمها، فستعمل التعليمات البرمجية بشكل عام، ولكنها قد تؤدي في بعض الأحيان إلى نتائج غريبة وسيكون من الصعب تعقب الخطأ.

إن بناء if (match = string.match(...)) يشبه خدعة استخدام المهمة كشرط في حلقة while. في كثير من الأحيان لا تعرف أن استدعاء المطابقة سينجح، لذا يمكنك فقط الوصول إلى الكائن الناتج داخل كتلة if التي تتحقق منه. لكي لا نكسر السلسلة الجميلة من عمليات التحقق، نقوم بتعيين نتيجة البحث لمتغير واستخدام هذا التعيين على الفور كفحص.

الرموز الدولية

نظرًا للتنفيذ البسيط للغة في البداية، والتثبيت اللاحق لمثل هذا التنفيذ "بالجرانيت"، فإن تعبيرات JavaScript العادية تكون غبية مع الأحرف غير الموجودة في اللغة الإنجليزية. على سبيل المثال، يمكن أن يكون حرف "الحرف"، من وجهة نظر تعبيرات JavaScript العادية، أحد الحروف الـ 26 للأبجدية الإنجليزية، ولسبب ما أيضًا شرطة سفلية. الحروف مثل é أو β، والتي من الواضح أنها أحرف، لا تتطابق مع \w (وسوف تتطابق مع \W، وهو غير حرف).

في تطور غريب، تاريخيًا \s (مسافة) تتطابق مع جميع الأحرف التي تعتبر مسافة بيضاء في Unicode، بما في ذلك أشياء مثل المسافة غير المنفصلة أو فاصل حرف العلة المنغولي.

تحتوي بعض تطبيقات regex في اللغات الأخرى على بنية خاصة للبحث عن فئات خاصة من أحرف Unicode، مثل "جميع الأحرف الكبيرة" أو "جميع علامات الترقيم" أو "أحرف التحكم". هناك خطط لإضافة مثل هذه الفئات إلى JavaScript، ولكن من المحتمل ألا يتم تنفيذها قريبًا.

الحد الأدنى

العناصر النظامية هي كائنات تمثل أنماط البحث في السلاسل. يستخدمون بناء الجملة الخاص بهم للتعبير عن هذه الأنماط.

/ اي بي سي / تسلسل الأحرف
// أي حرف من القائمة
/[^abc]/ أي حرف باستثناء الأحرف الموجودة في القائمة
// أي حرف من الفاصل الزمني
/x+/ تكرار واحد أو أكثر للنمط x
/x+?/ حدث واحد أو أكثر، غير جشع
/x*/ صفر أو أكثر
/x?/ صفر أو حدث واحد
/x(2,4)/ من مرتين إلى أربع مرات
/(اي بي سي)/ المجموعة
/a|b|c/ أي من الأنماط المتعددة
/\د/ أي رقم
/\w/ أي حرف أبجدي رقمي ("حرف")
/\s/ أي حرف مسافة بيضاء
/./ أي حرف باستثناء فواصل الأسطر
/\b/ حد الكلمة
/^/ بداية السطر
/$/ نهاية السطر

يحتوي التعبير العادي على طريقة اختبار للتحقق مما إذا كان النمط موجودًا في السلسلة. توجد طريقة exec تُرجع مصفوفة تحتوي على جميع المجموعات الموجودة. يحتوي المصفوفة على خاصية فهرس، والتي تحتوي على رقم الحرف الذي حدثت منه المطابقة.

تحتوي السلاسل على طريقة مطابقة لمطابقة الأنماط، وطريقة بحث تقوم بإرجاع موضع البداية للحدث فقط. يمكن للأسلوب استبدال استبدال تكرارات النمط بسلسلة أخرى. بالإضافة إلى ذلك، يمكنك تمرير وظيفة للاستبدال والتي ستنشئ سطرًا بديلًا استنادًا إلى القالب والمجموعات التي تم العثور عليها.

تحتوي الأحرف العادية على إعدادات مكتوبة بعد الشرطة المائلة للإغلاق. يجعل الخيار i التعبير العادي غير حساس لحالة الأحرف، والخيار g يجعله عموميًا، مما يؤدي، من بين أمور أخرى، إلى استبدال طريقة الاستبدال لجميع التكرارات التي تم العثور عليها، وليس فقط التكرار الأول.

يمكن استخدام مُنشئ RegExp لإنشاء تعبيرات عادية من السلاسل.

المنظمون أداة حادة ذات مقبض غير مريح. إنها تبسط بعض المهام إلى حد كبير، ويمكن أن تصبح غير قابلة للإدارة عند حل المشكلات المعقدة الأخرى. جزء من تعلم استخدام التعابير المنطقية هو القدرة على مقاومة إغراء إغراقهم بمهمة غير مخصصة لهم.

تمارين

حتمًا عند حل المشكلات، ستواجه حالات غير مفهومة، وقد تشعر باليأس أحيانًا عندما ترى السلوك غير المتوقع لبعض التعبيرات العادية. في بعض الأحيان يكون من المفيد دراسة سلوك محرك عادي من خلال خدمة عبر الإنترنت مثل debuggex.com، حيث يمكنك رؤية تصوره ومقارنته بالتأثير المطلوب.
الجولف العادي
"الجولف" في الكود هي لعبة تحتاج فيها إلى التعبير عن برنامج معين بأقل عدد من الأحرف. الجولف العادي هو تمرين عملي في كتابة أصغر اللاعبين المنتظمين الممكنين للعثور على نمط معين، وهذا فقط.

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

السيارة والقطة
- البوب ​​والدعامة
- النمس والعبارة والفيراري
- أي كلمة تنتهي بـ ious
- مسافة تليها نقطة أو فاصلة أو نقطتين أو فاصلة منقوطة.
- كلمة أطول من ستة أحرف
- كلمة بدون حروف ه

// أدخل التعبيرات النمطية الخاصة بك check(/.../, ["my car", "bad cats"], ["camper", "high art"]); تحقق(/.../, ["ثقافة البوب"، "الدعائم المجنونة"]، ["plop"]); check(/.../, ["ferret"، "ferry"، "ferrari"]، ["ferrum"، "transfer A"]); تحقق(/.../, ["كم هو لذيذ"، "غرفة واسعة"]، ["مدمر"، "الوعي"]); تحقق(/.../, ["علامات الترقيم سيئة."], ["الهروب من النقطة"]); تحقق(/.../, ["hottenottententen"], ["no", "hotten tottententen"]); تحقق(/.../, ["خلد الماء الأحمر"، "العش المتذبذب"]، ["سرير الأرض"، "قرد التعلم"]); التحقق من الوظيفة (regexp, Yes, no) ( // تجاهل التمارين غير المكتملة if (regexp.source == "...") return; Yes.forEach(function(s) ( if (!regexp.test(s)) console .log("لم يتم العثور على "" + s + """ )); no.forEach(function(s) ( if (regexp.test(s)) console.log("حدث غير متوقع "" + s + " "" ));

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

ابتكر نمطًا يميز بين هذين الاستخدامين لعلامات الاقتباس، واكتب استدعاءً للتابع استبدال الذي يقوم بالاستبدال.

الأرقام مرة أخرى
يمكن العثور على تسلسل الأرقام باستخدام تعبير عادي بسيط /\d+/.

اكتب تعبيرًا يبحث فقط عن الأرقام المكتوبة بأسلوب JavaScript. يجب أن يدعم علامة ناقص أو علامة زائد محتملة قبل الرقم والفاصلة العشرية والترميز العلمي 5e-3 أو 1E10 - مرة أخرى مع علامة زائد أو ناقص محتملة. لاحظ أيضًا أنه قد لا تكون هناك بالضرورة أرقام قبل النقطة أو بعدها، ولكن لا يمكن أن يتكون الرقم من نقطة واحدة. أي أن .5 أو 5. هي أرقام صالحة، لكن النقطة الواحدة في حد ذاتها ليست كذلك.

// أدخل التسلسل العادي هنا. رقم فار = /^...$/; // الاختبارات: ["1"، "-1"، "+15"، "1.55"، ".5"، "5."، "1.3e2"، "1E-4"، "1e+12"] .forEach(function(s) ( if (!number.test(s)) console.log("لم يتم العثور على "" + s + """); )); ["1a"، "+-1"، "1.2.3"، "1+1"، "1e4.5"، ".5."، "1f5"، "."].forEach(function(s) ( if (number.test(s)) console.log("تم قبوله بشكل غير صحيح "" + s + """); ));

التعبيرات العادية للمبتدئين

ما هي التعبيرات العادية؟

إذا سبق لك العمل مع سطر الأوامر، فمن المحتمل أنك استخدمت أقنعة أسماء الملفات. على سبيل المثال، لحذف جميع الملفات الموجودة في الدليل الحالي والتي تبدأ بالحرف "d"، يمكنك كتابة rm d* .

تعد التعبيرات العادية أداة مشابهة، ولكنها أكثر قوة للعثور على السلاسل، واختبارها مقابل نمط ما، وغيرها من الأعمال المشابهة. الاسم الإنجليزي لهذه الأداة هو التعبيرات العاديةأو ببساطة RegExp. بالمعنى الدقيق للكلمة، التعبيرات العادية هي لغة خاصة لوصف أنماط السلسلة.

يختلف تنفيذ هذه الأداة باختلاف لغات البرمجة، وإن لم يكن كثيرًا. سنركز في هذه المقالة بشكل أساسي على تنفيذ التعبيرات العادية المتوافقة مع Perl.

أساسيات بناء الجملة

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

ومع ذلك، يجب أن تكون حذرًا هنا - مثل أي لغة، تحتوي التعبيرات العادية على أحرف خاصة يجب تجاوزها. وهذه قائمتهم: . ^ $ * + ؟ ( ) \ | (). يتم الهروب بالطريقة المعتادة - بإضافة \ قبل الحرف الخاص.

مجموعة الأحرف

لنفترض أننا نريد العثور على جميع المداخلات في النص الذي يشير إلى الضحك. هاها لن يناسبنا - بعد كل شيء، "هيهي" و"هوهو" و"هيهي" لن تندرج تحتها. والمشكلة المتعلقة بحالة الحرف الأول يجب حلها بطريقة ما.

ستساعدنا المجموعات هنا - بدلاً من تحديد حرف معين، يمكننا كتابة قائمة كاملة، وإذا ظهر أي من الأحرف المدرجة في المكان المحدد في السلسلة التي يتم فحصها، فسيتم اعتبار السلسلة مناسبة. تتم كتابة الأنماط بين قوسين مربعين - سيتطابق النمط مع أي من الأحرف "a" أو "b" أو "c" أو "d".

داخل المجموعة ب يامعظم الأحرف الخاصة لا تحتاج إلى الهروب، ولكن استخدام \ أمامها لن يعتبر خطأ. لا يزال من الضروري الهروب من الأحرف "\" و"^"، ويفضل "]" (لذلك، فهذا يعني أيًا من الأحرف "]" أو "["، بينما [x] هو التسلسل "[" حصريًا" ×]"). يتم تحديد السلوك غير المعتاد على ما يبدو للتعبيرات العادية التي تحتوي على الحرف "]" في الواقع من خلال قواعد معروفة، ولكن من الأسهل بكثير الهروب من هذا الحرف بدلاً من تذكرها. بالإضافة إلى ذلك، يجب أن يتم الهروب من الرمز "-"، حيث يتم استخدامه لتعيين النطاقات (انظر أدناه).

إذا قمت بكتابة الرمز ^ مباشرة بعد [، فستأخذ المجموعة المعنى المعاكس - أي رمز غير تلك المحددة سيتم اعتباره مناسبًا. لذا، فإن النمط [^xyz] يطابق أي حرف باستثناء "x" أو "y" أو "z".

لذلك، بتطبيق هذه الأداة على حالتنا، إذا كتبنا [Xx] [aoie] x [aoie]، فإن كل سلسلة من السلاسل "Haha" و"hehe" و"hihi" وحتى "Hoho" سوف تتطابق مع النمط.

فئات الأحرف المحددة مسبقًا

بالنسبة لبعض المجموعات التي يتم استخدامها في كثير من الأحيان، هناك قوالب خاصة. لذلك، لوصف أي حرف مسافة بيضاء (مسافة، علامة تبويب، فاصل أسطر) يتم استخدام \s، للأرقام - \d، للأحرف اللاتينية، الأرقام والشرطات السفلية "_" - \w.

إذا كان من الضروري وصف أي شخصية على الإطلاق، يتم استخدام نقطة لهذا الغرض. . إذا تمت كتابة الفئات المحددة بحرف كبير (\S , \D , \W) فسوف يتغير معناها إلى العكس - أي حرف غير مسافات بيضاء، وأي حرف ليس رقمًا، وأي حرف آخر غير الأبجدية اللاتينية، والأرقام أو الشرطة السفلية، على التوالي.

أيضًا، باستخدام التعبيرات العادية، من الممكن التحقق من موضع السطر بالنسبة لبقية النص. يشير التعبير \b إلى حد الكلمة، \B إلى حد غير كلمة، و^ هو بداية النص، و$ هو النهاية. لذا، وفقًا لنمط \bJava\b، سيتم العثور على الأحرف الأربعة الأولى في السطر "Java وJavaScript"، ووفقًا لنمط \bJava\B - الأحرف من العاشر إلى الثالث عشر (كجزء من الكلمة " جافا سكريبت").

نطاقات

قد تحتاج إلى تعيين مجموعة تحتوي على أحرف، على سبيل المثال، من "b" إلى "f". بدلاً من كتابة [bvgdezziklmnoprstuf] يمكنك استخدام آلية النطاق وكتابة [b-f] . وبالتالي، فإن النمط x يتوافق مع السلسلة "xA6"، لكنه لا يتوافق مع "xb9" (أولاً، نظرًا لحقيقة أنه تتم الإشارة إلى الأحرف الكبيرة فقط في النطاق، وثانيًا، نظرًا لعدم تضمين 9 في الفترة 0 -8).

تعتبر آلية النطاق ذات صلة بشكل خاص باللغة الروسية، لأنه لا يوجد لها بناء مشابه لـ \w . لتعيين جميع حروف الأبجدية الروسية، يمكنك استخدام النمط [а-яА-ЯеО] . يرجى ملاحظة أن الحرف "е" غير مدرج في النطاق العام للأحرف ويجب تحديده بشكل منفصل.

محددات الكمية (تشير إلى عدد التكرارات)

دعنا نعود إلى مثالنا. ماذا لو كان المداخلة "الضاحكة" تحتوي على أكثر من حرف متحرك بين حرف x، مثل "هاهاها"؟ لن يكون موسمنا العادي القديم قادرًا على مساعدتنا. هنا سيتعين علينا استخدام محددات الكمية.

لاحظ أن المحدد الكمي ينطبق فقط على الحرف الذي يسبقه.

تلقت بعض الإنشاءات المستخدمة بشكل متكرر رموزًا خاصة في لغة التعبير العادية:

لذلك، بمساعدة أجهزة القياس الكمي، يمكننا تحسين نمطنا للتدخلات إلى [Xx] [aeeee] + x [aoeee] *، وسيكون قادرًا على التعرف على السلاسل "Haaha" و"heeeeeeh" و"Hihii".

القياس الكمي كسول

لنفترض أننا نواجه مهمة العثور على جميع علامات HTML في سلسلة ما

Tproger- لي محبوبموقع عن البرمجة!

الحل الواضح<.*>لن يعمل هنا - سيجد السلسلة بأكملها، لأنه يبدأ بعلامة الفقرة وينتهي بها. أي أن محتوى العلامة سيتم اعتباره سلسلة

ف> Tproger- لي محبوبموقع عن البرمجة!

يحدث هذا نظرًا لحقيقة أن المُحدِّد الكمي يعمل افتراضيًا وفقًا لما يسمى. طماعالخوارزمية - تحاول إرجاع أطول سلسلة ممكنة تطابق الشرط. هناك طريقتان لحل المشكلة. الأول هو استخدام التعبير<[^>]*> ، مما سيمنع اعتبار قوس الزاوية اليمنى محتوى العلامة. والثاني هو أن يعلن أن المحدد ليس الجشع، ولكن كسول. هل يتم ذلك عن طريق الإضافة إلى يمين محدد كمية الحرف؟ . أولئك. للبحث عن كافة العلامات، سيتم تحويل التعبير إلى<.*?> .

الكمي غيور

في بعض الأحيان، لزيادة سرعة البحث (خاصة في الحالات التي لا تتطابق فيها السلسلة مع التعبير العادي)، يمكنك منع الخوارزمية من العودة إلى خطوات البحث السابقة للعثور على التطابقات المحتملة لبقية التعبير العادي. تسمى غيورتحديد الكميات. يتم جعل المُحدِّد الكمي غيورًا عن طريق إضافة رمز + إلى اليمين. الاستخدام الآخر للقياس الكمي الغيور هو استبعاد المطابقات غير المرغوب فيها. وبالتالي، فإن النمط ab*+a في السلسلة "ababa" سيطابق الأحرف الثلاثة الأولى فقط، وليس الأحرف من الثالث إلى الخامس، لأن تم بالفعل استخدام الحرف "a" الموجود في الموضع الثالث للنتيجة الأولى.

مجموعات القوس

بالنسبة لقالب المداخلة "الضاحك" الخاص بنا، الشيء الصغير الوحيد المتبقي هو الأخذ في الاعتبار أن حرف "x" يمكن أن يظهر أكثر من مرة، على سبيل المثال، "هاهاهاهاهاهاهوو"، وقد ينتهي بحرف "x". ربما نحتاج إلى استخدام محدد كمي للمجموعة [aioe]+x هنا، ولكن إذا كتبنا فقط [aoie]x+ فإن المحدد الكمي + سينطبق فقط على الحرف "x" وليس على التعبير بأكمله. لإصلاح ذلك، يجب وضع التعبير بين قوسين: ([aioe]x)+ .

وبالتالي، يتحول تعبيرنا إلى [Xh]([аое]kh؟)+ - أولاً يوجد حرف كبير أو صغير "x"، ثم عدد اعتباطي غير صفري من حروف العلة، والتي (ربما، ولكن ليس بالضرورة) تتخللها مع حرف صغير واحد "x". ومع ذلك، فإن هذا التعبير لا يحل المشكلة إلا جزئيا - سيتضمن هذا التعبير أيضا خطوط مثل، على سبيل المثال، "hihaheh" - قد يضحك شخص ما، ولكن الافتراض مشكوك فيه للغاية. من الواضح أننا لا نستطيع استخدام مجموعة من حروف العلة إلا مرة واحدة، ومن ثم يجب علينا الاعتماد بطريقة أو بأخرى على نتيجة البحث الأول. ولكن كيف؟…

تذكر نتيجة البحث حسب المجموعة (ملاحظات)

اتضح أن نتيجة البحث عن مجموعة الأقواس يتم كتابتها في خلية ذاكرة منفصلة، ​​والتي يمكن الوصول إليها لاستخدامها في الأجزاء اللاحقة من التعبير العادي. بالعودة إلى مهمة البحث عن علامات HTML على الصفحة، قد لا نحتاج إلى العثور على العلامات فحسب، بل نحتاج أيضًا إلى معرفة أسمائها. يمكن أن يساعدنا التعبير العادي في هذا<(.*?)> .

Tproger- لي محبوبموقع عن البرمجة!

نتيجة البحث عن كافة التعبيرات العادية: "

”, “”, “”, “”, “”, “

”.
نتيجة البحث عن المجموعة الأولى: "ع"، "ب"، "/ب"، "ط"، "/i"، "/i"، "/p".

يمكن الإشارة إلى نتيجة البحث حسب المجموعة باستخدام التعبير \n، حيث n هو رقم من 1 إلى 9. على سبيل المثال، يتطابق التعبير (\w)(\w)\1\2 مع السلاسل "aaaa"، "abab" "، لكنه لا يتطابق مع "aabb."

إذا تم وضع تعبير بين قوسين فقط لتطبيق محدد الكمية عليه (لا توجد خطط لتذكر نتيجة البحث لهذه المجموعة)، فيجب إضافة القوس الأول على الفور?:، على سبيل المثال (?:+\w) .

باستخدام هذه الآلية، يمكننا إعادة كتابة التعبير إلى النموذج [Xx]([aoie])x?(?:\1x?)* .

تحويل

للتحقق مما إذا كانت السلسلة تلبي واحدًا على الأقل من الأنماط، يمكنك استخدام تناظري للعامل المنطقي OR، والذي يتم كتابته باستخدام الرمز | . وبالتالي، فإن نمط آنا | الوحدة يتضمن السطور "آنا" و"الوحدة" على التوالي. من الملائم بشكل خاص استخدام التعدادات داخل مجموعات الأقواس. لذا، على سبيل المثال، (?:a|b|c|d) مكافئ تمامًا (في هذه الحالة، الخيار الثاني هو الأفضل بسبب الأداء وسهولة القراءة).