عبارات باقاعده یا Regular Expressions / قسمت سوم (آخر)

نگاه مثبت به اطراف (Positive Lookaround)
چهار مورد بعدی اصطلاحاً اعلانهای(assertions) نگاه به جلو (  lookahead) یا نگاه به عقب ( lookbehind ) نامیده می شوند. این شکل گروه بندی ها در جستجوی کاراکترها یا عباراتی هستند که قبل یا بعد از تطبیق جاری می آیند، بدون اینکه خود زیر عبارت موجود در گروه در تطبیق شرکت کند. مهم است بدانید که این عبارتها موقعیت مانند "^" یا "b\" هیچ متنی را تطبیق نمی دهند. به همین دلیل این گروه بندی ها عنوان  "اعلانهای با طول- صفر" ( zero-width assertions ) شناخته می شوند(این گروه از ساختارها در اصل محل تطبیق را تعیین می کنند). بهترین راه برای درک اعلانهای طول- صفر استفاده از یک مثال است:

"(?=exp)"

 یک "اعلان نگاه مثبت به جلو با طول- صفر" (  zero-width positive lookahead assertions) است. این حالت وقتی به کار می رود که شما به دنبال عبارتهایی هستید که پسوند آنها exp است. حال اگر عبارتی وجود داشته باشد که پسوند آن exp باشد عبارت قبل از پسوند مذکور با عبارت قید شده قبل از

 "(?=exp)"

 تطبیق می شود و این در حالی است که خود پسوند در تطبیق شرکت نخواهد کرد. به مثال زیر توجه کنید:

22-    \b\w+(?=ing\b)
توضیح: این الگو به دنبال کلماتی می گردد که پسوند آنها ing باشد ولی خود ing را تطبیق نمی دهد.عبارت

"(?<=exp)"

یک "اعلان نگاه مثبت به عقب با طول- صفر" است. این ساختار برعکس ساختار قبلی به عقب نگاه می کند و اگر عبارت قبل از خود دارای پیشوند exp باشد عبارتی که بعد از پیشوند قرار گرفته است را با عبارت باقاعده ای که بعد از ساختار فوق می آید تطبیق می دهد ولی خود پیشوند (exp) در تطبیق شرکت نمی کند. به یک مثال توجه کنید:

23-    (?<=\bre)\w+\b
توضیح:  این الگو به دنبال کلماتی خواهد گشت که اولاً جدا از سایر کلمات بوده و جزئی از کلمه نباشند و ثانیاً دارای پیشوند "re" باشند. با استفاده از الگوی عبارت باقاعده زیر می توانید سه رقم انتهایی اعدادی را که بیش از سه رقم دارند را بیابید.

24-    (?<=\d)\d{3}\b
توضیح: سه رقم عددی انتهایی یک عبارت که قبل از آن یک رقم عددی وجود داشته باشد را تطبیق می دهد.

در مثال زیر از دو حالت نگاه به جلو و نگاه به عقب مثبت جهت یافتن پسوند و پیشوند استفاده شده است.

25-    (?<=\s)\w+(?=\s)
توضیح:  این الگو تمامی رشته های alphanumeric که به وسیله فضای خالی مرزبندی شده اند را تطبیق می دهد.

نگاه منفی به اطراف (Negative Lookaround)
پیشتر به شما نشان دادم که چگونه کاراکتری را که جز کاراکترهای خاص نیست یا اینکه عضو یک کلاس کاراکتر نیست جستجو کرده و پیدا کنید. حال اگر ما بخواهیم عدم حضور یک کاراکتر را مشخص کنیم ونیز نخواهیم هرچیزی را هم تطبیق دهیم چه کنیم؟ برای مثال برای یافتن کلماتی که حرف "q" داشته و بعد از آن حرف "u" حضور نداشته باشد چه باید کرد؟ الگوی زیر را بررسی کنیم:

26-    \b\w*q[^u]\w*\b
توضیح: مثال فوق را اجرا کنید و خواهید دید که اگر کاراکتر "q" آخرین حرف یک کلمه (مانند عبارت "Iraq" ) تطبیق شما جواب نخواهد داد و به این دلیل این اتفاق می افتد که "[u^]" سعی در تطبیق یک کاراکتر دارد. اگر "q" آخرین کاراکتر یک کلمه باشد، بعد از آن کاراکتر فضای خالی تطبیق خواهد یافت، بنابراین در این مثال عمل تطبیق عبارت باقاعده منتج به تطبیق دو کلمه کامل می شود. نگاه منفی به اطراف این مشکل را حل می کند چون که نگاه منفی به اطراف موقعیت را تطبیق داده و نیاز به تطبیق هر متنی ندارد. همانند آنچه که در نگاه مثبت به اطراف دیدیم نگاه منفی به اطراف می تواند به جای اینکه بتواند فقط یک تک کاراکتر را تطبیق دهد، موقعیت یک زیر عبارت پیچیده را به شکل دلخواهی تطبیق دهد. حالا بیایید سناریوی قبلی را به شکل زیر تست کنیم:


27-    \b\w*q(?!u)\w*\b
توضیح:  تمام کلماتی که دارای حرف "q" بوده و به دنبال آن "u" نیامده است می یابد.

ما از "اعلان نگاه به جلوی منفی با طول-صفر

" ( zero-width lookahead assertion )، "(?!exp)"

استفاده کردیم. این ساختار تنها در صورتی تطبیق موفق خواهد داشت که پسوند exp وجود نداشته باشد. مثال دیگر:

28-    \d{3}(?!\d) اعداد سه رقمی که بعد از آنها دیگر رقمی وجود نداشته باشد را تطبیق می دهد
به طور مشابه، می توانیم از

 "(?<!exp)"
،"اعلان نگاه به عقب منفی با طول - صفر" ( zero-width lookbehind assertion ) برای یافتن موقعیتی در متن که در آن پیشوند exp حضور نداشته باشد استفاده کنیم.

29-    (?<![a-z ])\w{7}
توضیح: رشته های هفت کاراکتری از نوع alphanumeric که پیش از آن حروف کوچک a تا z یا space وجود نداشته باشد را تطبیق می دهد.
(?<=<(\w+)>).*(?=<\/\1>)

30-   
توضیح:  این الگو متن بین تگ های HTML را شناسایی می کند. در این الگو از ساختار ارجاع به عقب استفاده شده است. همانگونه که قبلاً گفته شده زیرعبارت محصور شده "(+w\)" به طور اتوماتیک شماره گذاری می شود(در اینجا عدد یک به آن تخصیص داده می شود) و چون تگهای باز HTML می بایست در انتها بسته شوند با استفاده از "1\" یک ارجاع به عقب به زیر عبارت "(+w\)" می شود تا بالانس لازم انجام شود. شما می توانید به جای اینکه از شماره گذاری استفاده کنید از ساختار های دارای نام استفاده کنید. الگوی شماره 29 را می توانید به شکل زیر بنویسید:


31-   (?<=<(?<name>(\w+))>).*(?=<\/\k<name>>)
 توضیح:  در این الگو به زیر عبارت "(+w\)" نام name اختصاص داده شده است. حال اگر عبارت تطبیق داده شده در
 "\k<name>"

 برابر با عبارت تطبیق داده شده در "(\w+)" باشد عمل ارجاع به عقب تکمیل شده و کل عبارت داخل تگ HTML تطبیق داده خواهد شد. پیشنهاد می کنم عبارت فوق را با کدهای HTML و با استفاده از نرم افزار Expresso تست کنید.
این الگو یک تگ HTML را با استفاده از نگاه به عقب و متناظر با آن بسته شدن تگ را با استفاده از نگاه به جلو تطبیق می دهد بنابراین متون بین تگها تطبیق داده شده و به دام می افتند ولی تگها خیر.
لطفا توضیح دهید!
دیگر استفاده از پرانتزها نوشتن توضیحات برای سینتکسها مورد استفاده جهت الگوهای عبارت باقاعده است. ساختار این توضیحات به شکل "(?#Comment)" است. روش بهتر برای این کار تنظیم گزینه "Ignore Pattern Whitespace" است که اجازه می دهد فضاهای خالی داخل عبارتهای باقاعده وارد نمود و هنگامی که از عبارت باقاعده استفاده می شود فضاهای خالی در نظر گفته نمی شوند. با تنظیم این گزینه، از عبارتی که بعد از کاراکتر "#" (number sign) در انتهای هر خط متن قرار گرفته است چشم پوشی می شود. برای مثال می توانیم قالب بندی قبلی (یافتن متن بین تگها) را به شکل زیر بنویسیم:

 (?<=                # Search for a prefix, but exclude it
<(\w+)>             # Match a tag of alphanumeric within angle brackets
)                       # End the prefix
.*                      # Match any text
(?=                   # Search for a suffix, but exclude it
<\/\1>               # Match the previously captured tab preceded by "/"
)                       # End the suffix

حریص و تنبل (Greedy and Lazy)
وقتی یک عبارت باقاعده از کمیت سنجی استفاده می کند که می تواند تعداد تکرار را قبول کند (مانند ".*" )، رفتار معمول، تطبیق بیشترین تعداد کاراکتر ممکن است. عبارت باقاعده زیر را در نظر بگیرید:
32-    a.*b بلندترین رشته که با کاراکتر a آغاز شده و به b منتهی می شود را تطبیق می دهد.
توضیح: اگر از این الگو در رشته "aabab" به کار رود، الگو کل رشته "aabab" را تطبیق خواهد داد! این وضعیت را تطبیق "حریص" می نامند. برای اینکه بخواهیم حداقل تعداد تکرار را در یک رشته بیابیم لازم است ما از تطبیق "تنبل" استفاده کنیم. تمامی کمیت سنج های جدول 2 را می توان با افزودن علامت سئوال "?" به کمیت سنج "تنبل" تبدیل کرد. بنابراین "*?" به معنای "تطبیق هر تعداد تکرار است ولی از کمترین تعداد تکرار که باعث ایجاد یک تطبیق موفق می شود استفاه می کند". حالا اجازه بدید نسخه تنبل مثال 32 را بررسی کنیم:
33-    a.*?b کوتاهترین رشته ای که ابتدای آن حرف a و انتهای آن حرف b است را تطبیق می دهد.
توضیح: با به کار بردن الگوی فوق روی رشته "aabab" خواهید دید که اولین تطبیق "aab" و سپس "ab" خواهد بود.

*?            تکرار صفر یا بیشتر، با کمترین تعداد ممکن درست را تطبیق می دهد.
+?         تکرار یک یا بیشتر، با کمترین تعداد ممکن درست را تطبیق می دهد.
?           تکرار صفر یا یک با، اما کمترین تعداد ممکن درست را تطبیق می دهد.
{n,m}?   حداقل n و حداکثر m بار، اما کمترین تعداد ممکن درست را تطبیق می دهد.
{n,}?      حداقل n بار، اما کمترین تعداد ممکن دست را تطبیق می دهد.

آنچه که باقی مانده!
خلاصه ای از آنچه باقی مانده در جدول زیر آمده است. اکثر این المانها در(MSDN (Microsoft Developer Network تشریح گردیده است و می توانید جهت اطلاعات بیشتر به آن مراجعه کنید. در جدول زیر نیز کاربرد المانها ذکر شده است و برای درک عملکرد این المانها می توانید سری به project file نرم افزار Expresso بزنید.
What did we leave out

شمار ستون اول شامل شماره مثالهای موجود در project file است که چگونگی عملکرد ساختارها را نشان می دهد.
نتیجه گیری
مثالهای زیادی را برای نشان دادن ویژگیهای مهم و ضروری عبارات باقاعده در .NET Framework ارائه کردیم و بر استفاه از یک نرم افزار همانند Expresso  جهت تست و کسب تجربه جهت استفاده بهتر و درست از عبارات باقاعده به شما توصیه نمودیم.

البته مطالب زیادی باقی مانده است اگر مجالی بود و زنده ماندیم و از دعای خیر شما محروم نماندیم سعی در تکمیل و ارائه آنها خواهم نمود. همکنون در حال نوشتن کتابی در خصوص عبارات باقاعده و نیز معرفی کلاسها و توابع موجود در.NET Framework و چگونگی استفاده از آنها برای بهره مندی از الگوهای عبارات باقاعده می باشم. از کلیه بازدید کنندگان و دوستان محترم تقاضا دارم اگر نظری یا انتقادی در این خصوص دارند اعلام کنند و بنده را از راهنمایی ها خود محروم نسازند.