سفارش تبلیغ
صبا ویژن

در این مقاله می خواهم یکی از ساختارهای پیچده و بحث انگیز با عنوان تعریف گروه موازنه با استفاده از عبارت باقاعده را با ذکر مثالی برای شما تشریح کنم. سینتکس اصلی گروه موازنه به صورت:
(?<name1-naem2>subexpression) است. این ساختار تطبیق قبلی که به وسیله گروه name2 تعیین شده است را حذف می کند و در گروه name1 فاصله (interval) میان آنچه که گروه name2 تطبیق داده تا آنچه که گروه جاری (Balancing group) تطبیق داده است، ذخیره می کند. اگر در گروه name2 مقداری وجود نداشته باشد، عمل تطبیق عقبگرد خواهد کرد.( backtrack - قابلیت یک سیستم خبره در آزمایش راه حل های مختلف جهت یافتن یک پاسخ. راه حل های مختلف را می توان همچون شاخه های یک درخت تصور کرد. در این روش، برنامه مسیر یک شاخه را دنبال می کند و چنانچه بدون یافتن پاسخ به انتهای آن برد، به عقب بازگشته و شاخه دیگری را آزمایش می کند.) چون با حذفِ آخرین تطبیق انجام شده به وسیله name2، تطبیق قبلی که به وسیله name2 انجام گرفته شده است، نمایان می شود، این ساختار موجب می شود، پشته حاصل از capture های گروه name2 همانند یک شمارشگر (counter) عمل کند و از این شمارشگر می توان جهت ردیابی (Keep track of- دنبال کردن یک مسیر - در مدیریت داده ها به دنبال کردن جریان اطلاعات از طریق یک سیستم دستی یا خودکار گفته می شود.) ساختارهای تودرتو؛ مانند پرانتزها استفاده کرد (ساختارهای تودرتو یا nest- گنجاندن یک ساختار در یک ساختار دیگر. به عنوان مثال یک بانک اطلاعاتی ممکن است یک جدول تودرتو (جدولی در جدول دیگر)، یک برنامه ممکن است یک رویه تودرتو(رویه ای که در یک رویه دیگر تعریف شده باشد) و یک ساختار داده ای نیز ممکن یک رکورد تودرتو (رکوردی که حاوی فیلدی است که خود یک رکورد است) داشته باشد. در اینجا منظور ساختارهای تودرتو ایجاد شده به وسیله پرانتزها یا انواع براکتها می باشد.). در این ساختار، name1 اختیاری است؛ و می توان الگوی فوق را به شکل(?<-name2>subexp) نوشت. شما می توانید از single quote ها به جای angle brackets استفاده کنید. برای درک بهتر عملکرد این ساختار به مثالی که در همین قسمت ارائه شده توجه کنید:

  فرض کنیم ساختار تودرتویی که به وسیله براکتهای زوایه دار(<>)ایجاد شده اند را می خواهیم تطبیق دهیم. علت این که از براکتهای زاویه دار به جای پرانتز استفاده کرده ام این بوده که براکتها نیازی به escape کردن به وسیله"\"ندارند که خود موجب پیچیدگی بیشتر عبارت باقاعده می شود، بنابراین الگوی عبارت باقاعده ارائه شده ساده تر خواهد بود. می خواهیم بررسی کنیم که به ازای هر براکت باز"<" یک براکت بسته ">"وجود دارد یا خیر.

Regex

^[^<>]*(((?<Open><)[^<>]*)+((?<Close-Open>>)[^<>]*)+)*(?(Open)(?!))$

Sample Text and Search Result

<abc><mon<xyz>>

با توجه به پیچیدگی زیاد، الگوی فوق را به شکل زیر بازنویسی کرده ام. البته شما نمی توانید از ساختار زیر جهت تطبیق آنچه که در این مثال دنبال می کنیم استفاده کنید. شما با مراجعه به مقاله سوم عبارات باقاعده در وبلاگم، یاد خواهید گرفت که چگونه می توانید الگوهای خود را، همانند سایر کدنویسی هایتان با استفاده از فاصله گذاری های مناسب به شکل خوانایی درآورده و در برنامه های خود به کار ببرید.

  ^[^<>]*
  (
      (
            (?<Open><)[^<>]*
      )+
      (
            (?<Close-Open>>)[^<>]*
      )+
  )*
  (?(Open)(?!))
$

به منظور تشریح کامل الگوی فوق، از شماره بندی یا نامگذاری های الگوی فوق شروع می کنم:

شماره

نام پیش فرض

عبارت

0

0

کل عبارت باقاعده
1 1 (((?<Open><)[^<>]*)+((?<Close-Open>>)[^<>]*)+)
2 2  ((?<Open><)[^<>]*)
3 3  ((?<Close-Open>>)[^<>]*)
4 Open  (?<Open><)
  1. ابتدای الگو با zero-width،"^" آغاز شده است. پس رشته تطبیقی می بایست در ابتدای رشته قرار داشته باشد (یا در ابتدای خط در صورتی که گزینه Multiline فعال شود)

  2. [^<>]*هر نوع و به هر تعداد کاراکتر به جز "<>" را تطبیق می دهد.

  3. در اینجا به اولین گروه دارای شماره میرسیم. اولین گروه ما شماره ی 1 را به خود اختصاص داده است. گروه شماره یک به هر تعداد می تواند تکرار شود. گروه (((?<Open><)[^<>]*)+((?<Close-Open>>)[^<>]*)+)*  :1 شامل قسمتهای زیر است:

  4.             a) تکرار یک یا بیشتر گروه 2:    (?<Open><)[^<>]*)+
                         i) در گروه 2 یک زیرعبارت با نام Open وجود دارد که کاراکتر"<"را تطبیق می دهد. نام Open معادل name2 در ساختار گروه موازنه می باشد. بهتر است گروه Open همانند پشته ای حاصل از capture های انجام شده توسط همین گروه در نظر بگیریم که در این مثال رویدادهای "<" را در خود جادی می هد (یا push می کند). پس بالای پشته آخرین capture حاصل از گروه Open قرار دارد:(?<Open><)
                         [^<>]*ii) هر نوع و به هر تعداد کاراکتر به جز"<>" را تطبیق می دهد.
                         بنابراین گروه 2 تطبیق براکتهای باز"<" و هر آنچه به غیر از کاراکترهای "<>" را آنقدر ادامه می دهد تا اینکه به اولین براکت بسته ">"برسد. در اینجا نقش جالب گروه 3 که یک گروه موازنه است، آغاز می شود.
                b) تکرار یک یا بیشتر گروه 3: ((?<Close-Open>>)[^<>]*)+
                گروه 3 همانند گروه 2 از دو قسمت تشکیل شده است:
                         i) در گروه 3 یک ساختار موازنه (?<Close-Open>>) وجود دارد که براکت زاویه دار">" بسته را تطبیق می دهد و آخرین capture موجود در بالای پشته حاصل از گروه Open را حذف می کند (یا pop می کند). اگر پشته خالی باشد، تطبیق عقبگرد خواهد کرد. عمل pop از پشته گروه Open را می توان همانند یک شمارشگر در نظر گرفت و از آن در شناسایی ساختارهای تودرتو بهره جست. پس تا اینجا ما به ازای هر براکت بسته ">" یک براکت باز "<" از بالای پشته حذف کرده ایم.
                         [^<>]*  (ii  هر نوع و به هر تعداد کاراکتر به جز "<>" را تطبیق می دهد.
                         بنابراین گروه 3 نیز تطبیق براکتهای بسته ">" و هر آنچه غیر از کاراکترهای "<>" را آنقدر ادامه می دهد تا تمامی براکت بسته ">" به اتمام برسد.

    حال سئوال اینجاست که آیا به ازای هر براکت بسته یک براکت باز وجود داشته است یا خیر. دو حالت وجود دارد، اول اینکه تعداد براکتهای بسته بیشتر از براکتهای باز باشد. این مشکل با استفاده از گروه موازنه حل شده است. چون با دیدن هر براکت بسته یک براکت باز از پشته ه pop شده است. حال اگر تعداد براکتهای بسته بیشتر باشد چیزی برای pop کردن ا پشته وجود نخواهد داشت و تطبیق عقبگرد خواهد کرد تا تمامی مسیرهای ممکن دیگر را بیازماید و در صورت نیافتن براکت باز دیگر به ازای براکت یا براکتهای بسته ی اضافه ای که وجود دارد، عمل تطبیق ناموفق اعلام شده، شکست خواهد خورد. حالت دوم وقتی است که تعداد براکتهای باز بیش از براکتهای بسته باشد. در این حالت پشته capture های حاصل از گروه Open کاملا خالی نخواهد شد و جهت بررسی این حالت، آخرین قسمت الگو یعنی (?(Open)(?!)) ایفای نقش خواهد کرد.

  5.  زیر عبارت(?(Open)(?!)) یک نوع ساختار متناوب (Alternation) است. در برخی منابع این نوع ساختارها را ساختارهای شرطی نیز می نامند. سینتکس اصلی ساختار حاضر به صورت (?(name)yes|no) است. name نام یک گروه دارای ; name است. در این مثال نام گروه Open است. قسمت yes در صورت وجود capture ی در گروه name تطبیق می یابد. در غیر اینصورت قسمت no تطبیق پیدا خواهد کرد. قسمت no اختیاری است. پس (?!) در اصل همان قسمت yes ساختار متناوب (?(Open)(?!)) است. ما قبلاً در خصوص ساختار(?!) با شما صحبت کردیم. (عبارات باقاعده قسمت آخر). این ساختار یک نوع اعلان zero-width نگاه منفی به جلو است اما همانگونه که متوجه شدید سینتکس اصلی این ساختار به شکل(?!subexpression) است ولی در subexpression ،(?!) مشاهده نمی شود. بنابراین عبارت،(?(Open)(?!)) به موتور Regex دستور می دهد اگر گروه Open هنوز دارای یک capture از براکت باز است، (?!)را تطبیق دهد. یعنی تعداد براکتهای باز بیشتر از براکتهای بسته است و چون (?!) فاقد subexpression است، باید یک NULL را تطبیق دهد و این کار همواره موجب شکست عمل تطبیق الگوی عبارت باقاعده خواهد شد. در اصل این روش، اگر Open group هنوز حاوی یک capture باشد جهت ایجاد شکست به کار می رود.

  6. انتهای الگو نیز با zero-width، $ به اتمام می رسد. بنابراین رشته تطبیقی می باییست در انتهای رشته قرار داشته باشد (یا در ابتدای خط در صورتی که گزینه Multiline فعال شود.)


اولین دیدگاه را شما بگذارید ‍Regular Expressions ،

 حذف ردیف...   

مشخصات مدیر وبلاگ

محمد محمدی پیروز [33]

دل نوشته ها و تجربه های یک برنامه نویس
ویرایش

لوگوی دوستان



ویرایش

طراحی پوسته توسط تیم پارسی بلاگ