آموزش کار با عبارت منظم در PHP

به کمک عبارات منظم در برنامه‌نویسی می‌توانیم در یک رشته متنی الگوهای مورد نظر را بررسی کنیم. از عبارت منظم در PHP برای پیدا کردن الگوهای خاص یا اعتبارسنجی مقادیر رشته‌ای استفاده می‌شود. در این آموزش با الفبای اصلی Regex در PHP آشنا شده و توابع آن را یاد می‌گیریم.

در ابتدا کار بهتر است دقیق‌تر بفهمیم منظورمان از الگو (pattern) چیست ؟ با دو مثال هدف استفاده از ریجکس در php را توضیح می‌دهم.

فرض کنید یک متن در اختیار دارید و می‌خواهید وضعیت تکرار یک کلمه خاص در آن را بررسی کنید. مثلاً می‌خواهیم ببینیم کلمه «سبز دانش» چند بار در آن به کار برده شده است. این کار را می‌توانیم با روش‌های کار با رشته هم انجام دهیم.

ولی اگر کلمه مورد نظر ما پیچیده‌تر باشد چه ؟ مثلاً بخواهیم تعداد تکرار عبارت‌هایی را پیدا کنیم که با «س» شروع شده و با «نش» پایان می‌یابد. برای این کار مجبوریم از عبارت‌های منظم استفاده کنیم.

به همین شکل فرض کنید در یک فرم PHP فیلدی برای دریافت ایمیل دارید. ساختار ایمیل مشخص است اما تعداد حروف و حروف استفاده شده در آن برای هر نفر متفاوت است. برای اینکه مقدار وارد شده را اعتبارسنجی کنیم، از عبارات منظم در php استفاده خواهیم کرد.

تا به اینجا فهمیدیم که عبارت منظم چیست و چرا به دنبال یافتن آن هستیم. در ادامه با ساختار عبارات منظم و الفبای استفاده شده در آن می‌پردازیم و در انتها نیز توابع مهم Regex در PHP را بررسی خواهیم کرد.

عبارت منظم در PHP

بحث عبارات منظم یا Regular Expression فقط محدود به PHP نیست! در دروس رشته کامپیوتر یک ترم در مورد عبارات و ماشین‌های منظم صحبت می‌شود. معنا و مفهوم Regex (مخفف عبارات منظم) در همه جا یکسان است.

در اکثر زبان‌های برنامه‌نویسی سطح بالا توابعی برای بررسی ریجکس‌ها تعریف شده‌اند. الفبای تعریف یک عبارت منظم، در اکثر این زبان‌ها یکسان است. دلیل آن هم یادگیری و هماهنگی بیشتر میان زبان‌هاست.

سعی می‌کنم در این آموزش مفاهیم و علائم اصلی را بررسی کرده و لینک‌های مرجعی برای مطالعه بیشتر به شما ارائه کنم.

در یادگیری عبارات منظم در PHP دو مرحله اصلی داریم:

  1. تعریف الگو یا عبارت منظم
  2. استفاده از توابع عبارات منظم

ساختار عبارات منظم php

عبارت منظم در php یک رشته متنی است که از سه بخش اصلی تشکیل شده است: جداکننده، الگو و اصلاح‌کننده‌های اختیاری.

$exp = "/sabzdanesh/i";

در عبارت منظم بالا علامت / به عنوان جداکننده (delimiter)، کلمه sabzdanesh الگوی مورد نظر (pattern) و i یک اصلاح‌کننده (modifier) است که مشخص می‌کند الگوی ما به کوچکی یا بزرگی حروف حساس نیست.

جداکننده می‌تواند هر کاراکتری غیر از حروف، اعداد، فاصله (space) و \ باشد. معمولاً از علامت اسلش (/) در عبارات منظم استفاده می‌شود. اما در جاهایی که الگو دارای علامت slash هست از جداکننده‌های دیگر (مثل # یا ~) استفاده می‌شود.

الفبای عبارت منظم PHP

همانطور که گفتم، عبارات منظم یک زبان یا قاعده هستند. مانند هر زبان دیگری، عبارات منظم از الفبایی برای تعریف الگو استفاده می‌کند. می‌توان گفت باید این علائم را حفظ کنیم! البته به قدری ساده و مفهوم هستند که با چند بار استفاده از آن‌ها، بتوانیم یک Regex بنویسیم.

متاکاراکترها در ریجکس PHP

از متاکاراکترها (Meta Characters) برای مشخص کردن ویژگی همه یا بخشی از الگو استفاده می‌شود.

پر استفاده‌ترین علائم متا عبارت‌اند از:

  • ^ برای مشخص کردن شروع یک رشته متنی
  • $ برای مشخص کردن پایان رشته متنی
  • . (نقطه) یک کاراکتر نامشخص (هر کاراکتری می‌تواند جایگزین این علامت شود)
  • \ اگر در الگو از علائم خاص Regex وجود داشت، با قرار دادن \ قبل از آن کاراکتر، معنای ریجکسی آن را بی‌معنا می‌کنیم.
  • | به معنی «یا» بین کاراکترها استفاده می‌شود.

علامت نقطه به معنی وجود یک کاراکتر به جای آن است. یک عبارت منظم که مشخص کننده یک کلمه سه کاراکتری است به صورت /.../ تعریف می‌شود. این الگو برای abc یا s3e یا u%3 صدق خواهد کرد.

بررسی قواعد عبارات منظم (ریجکس یا Regex) برای php
بررسی قواعد عبارات منظم (ریجکس یا Regex) برای php

تعریف کاراکتر در عبارت منظم php

کاراکترها تقریباً اصلی‌ترین بخش یک عبارت منظم در PHP هستند. کاراکترها را می‌توان به صورت دقیق با به کار بردن همان کاراکتر در الگو تعریف کرد. برای مثال /ab/ الگویی است که یک کلمه دو حرفی ab را مشخص می‌کند.

کاراکترهای حروفی به صورت a و b و c تا z و عددی به صورت 0 و 1 تا 9 مشخص می‌شوند. چون حروف انگلیسی حساس به کوچکی و بزرگی هستند، مجموعه A تا Z را هم برای تعریف کاراکتر با حرف بزرگ در اختیار داریم.

در صورت نیاز می‌توان از کاراکترهای دیگر، مثل @ یا . هم استفاده کنیم. فقط توجه داشته باشید که اگر این کاراکتر جزء علائم Meta بود، قبل از آن‌ها از \ استفاده کنیم.

علامت . علامتی است که مشخص‌کننده فقط و فقط یک کاراکتر است.

گروه‌بندی و محدوده کاراکترها

واضح است که برای کاربردهای پیچیده، استفاده از خود کاراکتر بی معنا خواهد شد. بنابراین به کمک ۳ علامت مختلف، برای کاراکترها یک محدوده مشخص کرده یا آن‌ها را به صورت مجموعه تعریف می‌کنیم. این علائم در جدول زیر آورده شده‌اند:

برای مشخص کردن محدوده
()مشخص کننده یک گروه از کاراکترها
[]فقط یکی از کاراکترهای درون کروشه

فرض کنید می‌خواهیم در بخشی از یک عبارت منظم، استفاده از یک حرف کوچک انگلیسی را مشخص کنیم. برای تعریف مجموعه کاراکترها از a-z استفاده می‌کنیم. سپس این مجموعه را درون کروشه (قلاب) قرار می‌دهیم؛ به این معنی که فقط یکی از حروف این مجموعه مورد نظر ماست.

[a-z]

حال می‌خواهیم به جای تمام حروف انگلیسی، فقط چهار حرف s و a و b و z را داشته باشیم. کافی است این چهار حرف را کنار هم درون یک کروشه قرار دهیم.

[sabz]

عبارت منظم بالا برای عباراتی نظر s یا b یا z نتیجه مثبت و برای bz و مشابه آن جواب منفی خواهد داد.

فرض کنید می‌خواهیم یک عبارت با a یا b شروع شود. در ابتدای عبارت منظم مورد نظر خود در php گروه زیر را می‌نویسیم:

(a|b)

در این Regex از پرانتز برای گروه شدن محتوای درون آن استفاده شده است. به این عبارت پس از اتصالش به ابتدای ریجکس به صورت یک کاراکتر نگاه خواهد شد. همچنین از علامت | برای مشخص کردن «یا» استفاده شده است.

در عبارت منظم php زیر، یک الگو تعریف شده که: با a یا b شروع می‌شود، سپس یکی از اعداد 3 تا 7 را دارد و در نهایت با یکی از حروف بزرگ انگلیسی پایان یافته است.

$my_regex = "/(a|b)[3-7][A-Z]/"

الگو با کمیت‌های مقداری

علائم دیگری در عبارات منظم PHP داریم که به کمک آن‌ها تعداد کاراکترها در الگو را مشخص می‌کنیم. این علائم پس از یک کاراکتر یا گروه کاراکتر (پرانتز یا کروشه) قرار گرفته و تعداد مجاز تکرار آن قاعده را مشخص می‌کند.

*هیچ (0) یا بیشتر
+تعداد 1 بار یا بیشتر
?دقیقاً 0 یا 1 بار
{X}دقیقاً X بار
{X,}X یا بیشتر
{X,Y}بین X تا Y

اجازه دهید با چند مثال، درک این علائم را ساده‌تر کنم.

عبارت منظم ab+ یک رشته را مشخص می‌کند که حتماً با یک a شروع شده و پس از آن حداقل یک بار b قرار دارد.

عبارت منظم ab* رشته‌ای را مشخص می‌کند که با یک a شروع شده و پس از آن به تعداد دلخواهی b دارد. یعنی a و ab و abbbbb در این الگو پذیرفته می‌شوند.

عبارت منظم [a-z]+ رشته‌ای را مشخص می‌کند که تماماً از حروف کوچک انگلیسی تشکیل شده و حداقل یک کاراکتر دارد.

عبارت منظم [a-z]{3,5} رشته‌ای از حروف کوچک انگلیسی را مشخص می‌کند که حاوی ۳ یا ۴ یا ۵ کاراکتر است.

توابع مهم کار با عبارت منظم در PHP

مرحله پیچیده‌تر (سخت‌تر) کار با عبارات منظم در PHP تمام شد! حال که توانستیم یک الگوی ریجکس برای اعتبارسنجی رشته متنی خود بنویسیم، کافی است به کمک ۳ تابعی که در ادامه معرفی می‌شود، رشته متنی خود را ارزیابی کنیم.

بررسی وجود الگو با preg_match

تابع preg_match() پنج پارامتر ورودی می‌گیرد. دو پارامتر اول اجباری و ۳ تای بعدی اختیاری است.

این تابع در ورودی اول الگوی مورد نظر و در دومین پارامتر رشته‌ای که باید در آن جستجو کند را دریافت می‌کند. اگر رشته مطابق با الگو بود، مقدار true و در غیراینصورت false به عنوان خروجی می‌دهد.

preg_match( string $pattern, string $subject, array &$matches, int $flags, int $offset );

ورودی‌های اختیاری این تابع عبارت‌اند از:

  • پارامتر سوم ($matches) جستجوهای پیدا شده را در خود نگه می‌دارد. باید یک آرایه به این ورودی بدهیم.
  • در صورت 1 قرار دادن پارامتر چهارم ($flags) اندیس شروع عبارات مطابق الگو را به ما برمی‌گرداند.
  • اگر بخواهیم جستجوی الگو از یک اندیس خاص به بعد در رشته انجام شود، مقدار اندیس را به عنوان ورودی آخر ($offset) تعریف می‌کنیم.

فرض کنید رشته $str را داریم. در قطعه کد زیر، اگر کلمه‌ای مطابق با الگوی $pattern پیدا شد، پیام founded و در غیر اینصورت not founded چاپ می‌شود.

$str = "Hi! This a test for PHP Regex find from sabzdanesh site. have a nice time!";
$pattern = "/.es/";
$result = preg_match( $pattern, $str );

if( $result )
    echo "pattern founded!";
else
    echo "pattern not founded!";

وقتی این کد را اجرا کنیم، نتیجه نهایی founded خواهد بود. چون در دو جا (test و sabzdanesh) الگوی .es آورده شده است.

حال برای پارامتر سوم متغیر $occurs را قرار داده و کد را اجرا می‌کنیم. با این تفاوت که در صورت پیدا کردن الگو، آرایه occurs را چاپ می‌کنیم.

$str = "Hi! This a test for PHP Regex find from sabzdanesh site. have a nice time!";
$pattern = "/.es/";
$result = preg_match( $pattern, $str, $occurs );

if( $result )
    print_r( $occurs );
else
    echo "pattern not founded!";

نتیجه کد بالا چیزی شبیه زیر خواهد بود:

Array ( [0] => tes )

به نظر شما چرا در نتایج پیدا شده، دومین مقداری که با الگو مطابق داشت آورده نشده؟

تابع preg_match() فقط اولین تطابق را پیدا کرده و آن را به عنوان نتیجه به ما بازمی‌گرداند.

شمارش تکرار با preg_match_all

تابع preg_match_all() دقیقاً مشابه تابع قبلی عمل می‌کند با این تفاوت که همه مطابقت‌ها را به عنوان خروجی به ما برمی‌گرداند.

با اجرای قطعه کد زیر، هر دو مقداری که مطابق با الگوی ما در رشته بود، در آرایه occurs قرار گرفته‌اند.

$str = "Hi! This a test for PHP Regex find from sabzdanesh site. have a nice time!";
$pattern = "/.es/";
preg_match( $pattern, $str, $occurs );
print_r( $occurs );
//Output:
// Array ( [0] => tes [1] => nes )

جایگزین کردن الگو با preg_replace

در ترفندهای کار با رشته در PHP با تابعی برای جایگزینی یک کلمه با کلمه‌ای دیگر در رشته آشنا شدیم. اگر بخواهیم مشابه همان کار را با الگوها انجام دهیم از تابع preg_replace() استفاده خواهیم کرد.

سه پارامتر اول ورودی این تابع اجباری است. اولین پارامتر مشخص‌کننده الگوی جستجو، دومین پارامتر عبارتی که باید جایگزین الگو شود و سومین پارامتر رشته‌ای است که می‌خواهیم در آن عملیات جایگزینی انجام شود.

$str = "I have been used php5 for 3 years. But now i use php7 instead of.";
$pattern = "/php[3-8]/";
$result = preg_replace( $pattern, "python", $str );

با اجرای قطعه کد بالا، به جای php5 و php7 عبارت python جایگزین خواهد شد.

خروجی این تابع یک رشته متنی است که تغییرات مورد نظر ما در آن اعمال شده است.

اگر می‌خواهید مثال‌های پیچیده‌تری از عبارات منظم در php بخوانید یا با علامت‌های بیشتری آشنا شوید، به صفحه مستندات آن مراجعه کنید.