Group و Capturing Group: استخراج بخش‌های مشخصی از یک تطابق

در درس قبل با ساخت الگوهای عبارت باقاعده برای بررسی صحت یک رشته آشنا شدید. اما گاهی هدف صرفاً تأیید یا رد یک رشته نیست، بلکه استخراج بخش‌های مشخصی از آن است؛ مثلاً جدا کردن کد کشور، کد شهر و شماره‌ی اصلی از یک شماره تلفن. Group و Capturing Group دقیقاً برای همین منظور طراحی شده‌اند.

Group: گروه‌بندی بخشی از الگو با پرانتز

پرانتز () در یک عبارت باقاعده، بخشی از الگو را به‌عنوان یک واحد گروه‌بندی می‌کند؛ این گروه‌بندی هم امکان اعمال Quantifier روی چند کاراکتر هم‌زمان را می‌دهد و هم—که مهم‌تر است—آن بخش را برای استخراج بعدی علامت‌گذاری می‌کند:

const pattern = /(ab)+/;

console.log(pattern.test("ababab")); // true؛ گروه "ab" سه بار تکرار شده
console.log(pattern.test("a"));      // false

Capturing Group: استخراج مقدار با متد match

هر گروه داخل پرانتز، به‌طور پیش‌فرض یک Capturing Group است؛ یعنی مقداری که با آن بخش از الگو مطابقت پیدا کرده، ذخیره و قابل استخراج می‌شود. برای این کار، متد match روی رشته فراخوانی می‌شود:

استخراج بخش‌های یک تاریخ با Capturing Group
خروجی کنسول اینجا نمایش داده می‌شود...

نکته‌ی مهم این است که اندیس 0 در آرایه‌ی نتیجه، همیشه کل بخش تطابق‌یافته را نشان می‌دهد، نه یک Capturing Group؛ گروه‌های واقعی از اندیس 1 شروع می‌شوند و دقیقاً به همان ترتیبی هستند که پرانتزها در الگو نوشته شده‌اند.

Named Capturing Group: نام‌گذاری گروه‌ها برای خوانایی بیشتر

دسترسی به گروه‌ها فقط با اندیس عددی، به‌خصوص در الگوهای پیچیده، خوانایی کد را کاهش می‌دهد. جاوااسکریپت امکان نام‌گذاری هر Capturing Group را با نحو (?<name>...) فراهم می‌کند:

const datePattern = /(?\d{4})-(?\d{2})-(?\d{2})/;

const result = "1404-05-12".match(datePattern);

console.log(result.groups.year);  // "1404"
console.log(result.groups.month); // "05"
console.log(result.groups.day);   // "12"

شیء groups در نتیجه‌ی match، شامل تمام Named Capturing Groupها بر اساس نام آن‌هاست و کد را به‌طور محسوسی خواناتر می‌کند، به‌خصوص وقتی تعداد گروه‌ها زیاد باشد.

Non-Capturing Group: گروه‌بندی بدون استخراج

گاهی فقط نیاز به گروه‌بندی برای اعمال Quantifier است، بدون آنکه نیازی به استخراج مقدار آن گروه باشد. برای این منظور، از نحو (?:...) استفاده می‌شود که یک Non-Capturing Group می‌سازد:

const pattern = /(?:https?:\/\/)?(\w+\.\w+)/;

const result = "https://greendata.ir".match(pattern);

console.log(result[0]); // "https://greendata.ir"
console.log(result[1]); // "greendata.ir"؛ فقط همین یک گروه capturing است

در این مثال، بخش (?:https?:\/\/)? فقط برای بررسی وجود اختیاری پروتکل استفاده شده و در نتیجه‌ی match ظاهر نمی‌شود؛ در حالی که اگر همین بخش با پرانتز معمولی نوشته می‌شد، یک اندیس اضافی و غیرضروری در نتیجه ایجاد می‌کرد.

جدول مقایسه‌ی انواع Group

نوع Group نحو در نتیجه‌ی match ظاهر می‌شود؟
Capturing Group (...) بله، با اندیس عددی
Named Capturing Group (?<name>...) بله، هم با اندیس و هم در groups.name
Non-Capturing Group (?:...) خیر

نکات کلیدی

  • پرانتز در یک عبارت باقاعده، بخشی از الگو را گروه‌بندی کرده و آن را به‌طور پیش‌فرض قابل استخراج (capturing) می‌کند.
  • در نتیجه‌ی match، اندیس 0 کل تطابق است و Capturing Groupها از اندیس 1 شروع می‌شوند.
  • Named Capturing Group با نحو (?<name>...) امکان دسترسی خواناتر به گروه‌ها از طریق شیء groups را فراهم می‌کند.
  • Non-Capturing Group با نحو (?:...) فقط برای گروه‌بندی بدون نیاز به استخراج مقدار استفاده می‌شود.

جمع‌بندی

Capturing Group ابزار اصلی استخراج بخش‌های مشخص از یک رشته‌ی مطابق با الگو است، و نام‌گذاری این گروه‌ها با Named Capturing Group، خوانایی کد را در الگوهای پیچیده به‌طور قابل‌توجهی بهبود می‌دهد. Non-Capturing Group نیز برای مواردی که فقط ساختار الگو مهم است، نه استخراج مقدار، گزینه‌ای تمیزتر ارائه می‌دهد. در درس بعدی، متدهای عملی‌تری مثل replace و matchAll برای کار گسترده‌تر با این گروه‌ها بررسی خواهد شد.