يمكن وضع جزء من النموذج بين قوسين نمط: (...)
. وهذا ما يسمى “مجموعة أسر”.
هذا له تأثيران:
- يسمح بالحصول على جزء من المباراة كبند منفصل في مصفوفة النتائج.
- إذا وضعنا كمياً بعد الأقواس ، فإنه ينطبق على الأقواس ككل.
الأمثلة
دعونا نرى كيف تعمل الأقواس في الأمثلة.
مثال: gogogo
بدون قوسين ، فإن النمط النمط: go +
يعني الموضوع: g
، متبوعًا بـالموضوع: o
مكررًا مرة واحدة أو أكثر. على سبيل المثال ، goooo
أو gooooooooo
.
تجمع الأقواس الأحرف معًا ، لذا النمط: (go) +
يعني go
و gogo
و gogogo
وما إلى ذلك.
alert( 'Gogogo now!'.match(/(go)+/ig) ); // "Gogogo"
مثال: المجال
دعونا نجعل شيئًا أكثر تعقيدًا – تعبيرًا عاديًا للبحث عن نطاق موقع ويب.
فمثلا:
mail.com
users.mail.com
smith.users.mail.com
كما نرى ، المجال يتكون من كلمات متكررة ، نقطة بعد كل واحدة باستثناء الأخيرة.
في التعبيرات العادية هذا نمط: (\ w + \.) + \ w +
:
let regexp = /(\w+\.)+\w+/g;
alert( "site.com my.site.com".match(regexp) ); // site.com,my.site.com
يعمل البحث ، ولكن لا يمكن أن يتطابق النمط مع النطاق بواصلة ، على سبيل المثال my-site.com
، لأن الواصلة لا تنتمي إلى النمطclass: \ w
.
يمكننا إصلاحه عن طريق استبدال \ w
بـ [\ w-]
في كل كلمة باستثناء الكلمة الأخيرة: ([\ w -] + \.) + \ w +
.
مثال: البريد الإلكتروني
يمكن توسيع المثال السابق. يمكننا إنشاء تعبير عادي للرسائل الإلكترونية بناءً عليه.
تنسيق البريد الإلكتروني هو: name @ domain
. يمكن أن تكون أي كلمة الاسم والواصلات والنقاط مسموحًا بها. في التعبيرات العادية هذا النمط: [-. \ w] +
.
النمط:
let regexp = /[-.\w]+@([\w-]+\.)+[\w-]+/g;
alert("my@mail.com @ his@site.com.uk".match(regexp)); // my@mail.com, his@site.com.uk
هذا التعبير العادي ليس مثاليًا ، ولكنه يعمل في الغالب ويساعد على إصلاح الأخطاء العرضية. لا يمكن إجراء الاختيار الوحيد الموثوق به حقًا للبريد الإلكتروني إلا عن طريق إرسال بريد إلكتروني.
أقواس المحتويات في المباراة
الأقواس مرقمة من اليسار إلى اليمين. يحفظ محرك البحث المحتوى المطابق لكل منها ويسمح بالحصول عليه في النتيجة.
الطريقة str.match (regexp)
، إذا لم يكن لـ regexp
علامةg
، فابحث عن المطابقة الأولى وترجعها كمصفوفة:
- في الفهرس
0
: المباراة الكاملة. - في الفهرس
1
: محتويات الأقواس الأولى. - في الفهرس
2
: محتويات الأقواس الثانية. - … وهكذا …
على سبيل المثال ، نود العثور على علامات HTML <. *؟>
، ومعالجتها. سيكون من المناسب وجود محتوى علامة (ما يوجد داخل الزوايا) ، في متغير منفصل.
دعونا نلف المحتوى الداخلي بين قوسين ، مثل هذا: <(. *؟)>
.
الآن سنحصل على كل من العلامة على أنها مطابقة كاملة: <h1>
ومحتوياتها مطابقة: h1
في الصفيف الناتج:
let str = '<h1>Hello, world!</h1>';
let tag = str.match(/<(.*?)>/);
alert( tag[0] ); // <h1>
alert( tag[1] ); // h1
المجموعات المتداخلة
يمكن أن تتداخل الأقواس. في هذه الحالة ، ينتقل الترقيم أيضًا من اليسار إلى اليمين.
على سبيل المثال ، عند البحث عن علامة في الموضوع: <span class =" my ">
قد نكون مهتمين بما يلي:
- محتوى العلامة ككل:
span class =" my "
. - اسم العلامة:
span
. - سمات العلامة:
class =" my "
.
دعونا نضيف أقواسًا لهم: <(([a-z] +) \ s * ([^>] *))>
.
إليك كيفية ترقيمها (من اليسار إلى اليمين ، عن طريق قوس الافتتاح):
In action:
let str = '<span class="my">';
let regexp = /<(([a-z]+)\s*([^>]*))>/;
let result = str.match(regexp);
alert(result[0]); // <span class="my">
alert(result[1]); // span class="my"
alert(result[2]); // span
alert(result[3]); // class="my"
دائمًا ما يحمل الفهرس الصفري “النتيجة” المطابقة الكاملة.
ثم المجموعات ، مرقمة من اليسار إلى اليمين بواسطة قوس افتتاح. تم إرجاع المجموعة الأولى على أنها نتيجة [1]
. هنا يرفق محتوى العلامة بالكامل.
ثم في النتيجة [2]
تنتقل المجموعة من نمط `` الفتح الثاني ‘’: ([az] +) - اسم العلامة ، ثم في
النتيجة [3] العلامة:
النمط: ([^>] * ) `.
محتويات كل مجموعة في السلسلة:
المجموعات الاختيارية
حتى إذا كانت المجموعة اختيارية ولا وجود لها في المطابقة (على سبيل المثال ، تحتوي على النموذج المُحدِّد الكمي: (...)؟
) ، فإن عنصر صفيف النتيجة
المطابق موجود ويساويغير معرّف
.
على سبيل المثال ، دعنا نفكر في regexp a (z)؟ (c)؟
. تبحث عن “” “متبوعًا اختياريًا بـ” “z” “متبوعًا اختياريًا بـ” “c” ".
إذا قمنا بتشغيله على السلسلة بحرف واحد a
، فإن النتيجة هي:
let match = 'a'.match(/a(z)?(c)?/);
alert( match.length ); // 3
alert( match[0] ); // a (whole match)
alert( match[1] ); // undefined
alert( match[2] ); // undefined
الصفيف له طول 3
، لكن كل المجموعات فارغة.
وإليك مطابقة أكثر تعقيدًا للسلسلة ac
:
let match = 'ac'.match(/a(z)?(c)?/)
alert( match.length ); // 3
alert( match[0] ); // ac (whole match)
alert( match[1] ); // undefined, because there's nothing for (z)?
alert( match[2] ); // c
طول الصفيف دائم: 3
. ولكن لا يوجد شيء للمجموعة 'pattern: (z)؟ ، لذا فإن النتيجة هي" ["ac"، undefined، "c"]
.
البحث عن جميع التطابقات مع المجموعات: matchAll
matchAll
هي طريقة جديدة ، قد تكون هناك حاجة إلى تعبئة متعددةالطريقة matchAll
غير مدعومة في المتصفحات القديمة.
قد تكون هناك حاجة إلى تعبئة متعددة ، مثل https://github.com/ljharb/String.prototype.matchAll.
عندما نبحث عن جميع التطابقات (الإبلاغ عن g
) ، لا تُرجع طريقةmatch
محتويات المجموعات.
على سبيل المثال ، دعنا نجد كل العلامات في سلسلة:
let str = '<h1> <h2>';
let tags = str.match(/<(.*?)>/g);
alert( tags ); // <h1>,<h2>
والنتيجة هي مجموعة من التطابقات ، ولكن بدون تفاصيل حول كل منها. ولكن في الممارسة العملية ، نحتاج عادةً إلى محتويات مجموعات الالتقاط في النتيجة.
للحصول عليها ، يجب البحث باستخدام الطريقة str.matchAll (regexp)
.
تمت إضافتها إلى لغة جافا سكريبت بعد فترة طويلة من “التطابق” ، باعتبارها “نسختها الجديدة والمحسنة”.
تمامًا مثل match
، فإنه يبحث عن المباريات ، ولكن هناك 3 اختلافات:
- لا تقوم بإرجاع صفيف ، ولكن كائن قابل للتكرار.
- عند وجود العلامة “pattern: g” ، فإنها تُرجع كل مطابقة كمصفوفة بمجموعات.
- في حالة عدم وجود تطابقات ، فإنها لا تُرجع “قيمة خالية” ، بل تُرجع كائنًا فارغًا قابلًا للتكرار.
على سبيل المثال:
let results = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
// results - is not an array, but an iterable object
alert(results); // [object RegExp String Iterator]
alert(results[0]); // undefined (*)
results = Array.from(results); // let's turn it into array
alert(results[0]); // <h1>,h1 (1st tag)
alert(results[1]); // <h2>,h2 (2nd tag)
كما نرى ، فإن الفرق الأول مهم للغاية ، كما هو موضح في السطر (*)
. لا يمكننا الحصول على المطابقة كـ "النتائج [0]، لأن هذا الكائن ليس كاذبًا. يمكننا تحويلها إلى
Arrayحقيقي باستخدام
Array.from`. هناك المزيد من التفاصيل حول المصفوفات الكاذبة والقابلة للتكرار في المقالة <info: iterable>.
ليست هناك حاجة في Array.from
إذا كنا نراجع النتائج:
let results = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
for(let result of results) {
alert(result);
// first alert: <h1>,h1
// second: <h2>,h2
}
… أو باستخدام الـ destructuring
:
let [tag1, tag2] = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
كل مطابقة ، يتم إرجاعها بواسطة matchAll
، لها نفس التنسيق الذي تم إرجاعه بواسطةمطابقة
بدون نمط العلامة: g
: إنها مصفوفة ذات خصائص إضافيةفهرس
(فهرس المطابقة في السلسلة) و الإدخال
(سلسلة المصدر ):
let results = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
let [tag1, tag2] = results;
alert( tag1[0] ); // <h1>
alert( tag1[1] ); // h1
alert( tag1.index ); // 0
alert( tag1.input ); // <h1> <h2>
لماذا تم تصميم الطريقة بهذه الطريقة؟ والسبب بسيط – للتحسين.
استدعاء “matchAll” لا يجري البحث. بدلاً من ذلك ، تقوم بإرجاع كائن قابل للتكرار ، بدون النتائج في البداية. يتم إجراء البحث في كل مرة نكرر فيها ذلك ، على سبيل المثال في الحلقة.
لذلك ، سيتم العثور على العديد من النتائج حسب الحاجة ، وليس أكثر.
على سبيل المثال من المحتمل أن يكون هناك 100 تطابق في النص ، ولكن في حلقة for..of
وجدنا 5 منها ، ثم قررنا أنها كافية وقمنا بعمل" break
".ثم لن يقضي المحرك وقتًا في العثور على 95 تشابه آخر.
المجموعات المسماة
من الصعب تذكر المجموعات بأرقامها. بالنسبة للأنماط البسيطة ، يمكن القيام بذلك ، ولكن بالنسبة للأنماط الأكثر تعقيدًا ، يعد حساب الأقواس غير مريح. لدينا خيار أفضل بكثير: إعطاء أسماء للأقواس.
يتم ذلك عن طريق وضع "pattern :؟
على سبيل المثال ، دعنا نبحث عن تاريخ بتنسيق “عام-شهر-يوم”:
let dateRegexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/;
let str = "2019-04-30";
let groups = str.match(dateRegexp).groups;
alert(groups.year); // 2019
alert(groups.month); // 04
alert(groups.day); // 30
كما ترى ، المجموعات موجودة في خاصية “.groups” للمباراة.
للبحث عن جميع التواريخ ، يمكننا إضافة العلم g
.
سنحتاج أيضًا إلى “matchAll” للحصول على تطابقات كاملة ، جنبًا إلى جنب مع المجموعات:
let dateRegexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/g;
let str = "2019-10-30 2020-01-01";
let results = str.matchAll(dateRegexp);
for(let result of results) {
let {year, month, day} = result.groups;
alert(`${day}.${month}.${year}`);
// first alert: 30.10.2019
// second: 01.01.2020
}
الاستيلاء على المجموعات في الاستبدال
تسمح الطريقة str.replace (regexp ، الاستبدال)
التي تستبدل جميع التطابقات بـ regexp
فيstr
باستخدام محتويات الأقواس في سلسلة replace
. يتم ذلك باستخدام $ n
، حيث n
هو رقم المجموعة.
فمثلا،
let str = "John Bull";
let regexp = /(\w+) (\w+)/;
alert( str.replace(regexp, '$2, $1') ); // Bull, John
بالنسبة للأقواس المسماة ، سيكون المرجع $ <name>
.
على سبيل المثال ، دعنا نعيد تنسيق التواريخ من “year-month-day” إلى “day.month.year”:
let regexp = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/g;
let str = "2019-10-30, 2020-01-01";
alert( str.replace(regexp, '$<day>.$<month>.$<year>') );
// 30.10.2019, 01.01.2020
المجموعات غير الملتقطة مع؟:
في بعض الأحيان نحتاج إلى قوسين لتطبيق مُحدِّد الكمية بشكل صحيح ، لكننا لا نريد محتوياتها في النتائج.
يمكن استبعاد مجموعة بإضافة “pattern:؟:” في البداية.
على سبيل المثال ، إذا أردنا العثور على "pattern: (go) +، لكننا لا نريد محتويات الأقواس (
go) كعنصر صفيف منفصل ، فيمكننا كتابة:
pattern :( ؟: go) + ` .
في المثال أدناه ، نحصل فقط على الاسم John
كعضو منفصل في المباراة:
let str = "Gogogo John!";
// ?: exludes 'go' from capturing
let regexp = /(?:go)+ (\w+)/i;
let result = str.match(regexp);
alert( result[0] ); // Gogogo John (full match)
alert( result[1] ); // John
alert( result.length ); // 2 (no more items in the array)
الملخص
تجمع الأقواس معًا جزءًا من التعبير العادي ، بحيث ينطبق المقياس عليه ككل.
يتم ترقيم مجموعات الأقواس من اليسار إلى اليمين ، ويمكن اختياريًا تسميتها بـ (؟ <name> ...)
.
يمكن الحصول على المحتوى المطابق لمجموعة ما في النتائج:
- تُظهر الطريقة
str.match
مجموعات الالتقاط فقط بدون وضع علامة على" النموذج: g`. - الطريقة
str.matchAll
تُرجع دائمًا مجموعات الالتقاط.
إذا لم يكن للأقواس اسم ، فإن محتوياتها متاحة في مصفوفة المطابقة برقمها. الأقواس المسموعة متاحة أيضًا في خاصية “المجموعات”.
يمكننا أيضًا استخدام محتويات الأقواس في سلسلة الاستبدال في str.replace
: بالرقم$ n
أو بالاسم $ <name>
.
يمكن استبعاد مجموعة من الترقيم عن طريق إضافة “pattern:؟:” في بدايتها. يُستخدم هذا عندما نحتاج إلى تطبيق مُحدِّد الكمية على المجموعة بأكملها ، ولكن لا نريدها كبند منفصل في صفيف النتائج. لا يمكننا أيضًا الإشارة إلى هذه الأقواس في سلسلة الاستبدال.