۶ عبارت منظم و کاربردشان در جاوا اسکریپت – راهنمای کاربردی


تقریباً همه زبانهای برنامهنویسی محبوب از عبارتهای منظم پشتیبانی میکنند و این مسئله نیز بیجهت نیست چون عبارتهای منظم ابزارهای قدرتمندی در اختیار توسعهدهندگان هستند و آنها را قادر میسازند که وظایف سنگینی را که به دهها خط کدنویسی نیاز دارد را به صورت سریع و بهینهای به اجرا درآورند. در این مقاله با 6 عبارت منظم و کاربردشان در جاوا اسکریپت آشنا خواهیم شد.
یافتن جملههایی شامل یک کلمه خاص
فرض کنید میخواهید همه جملههای یک متن را که دارای یک کلمه خاص هستند پیدا کنید.
مثلاً شاید میخواهید جملهها را در نتایج جستجو نشان دهید یا شاید بخواهید آنها را از متن حذف کنید. regex زیر امکان انجام این کار را فراهم میسازد:
/[^.!?]*\bword\b[^.!?]*.?/gi
طرز کار آن در عمل صورت زیر است:
1const str = "The apple tree originated in Central Asia. It is cultivated worldwide. Apple matures in late summer or autumn.";
2// en.wikipedia.org/wiki/Apple
3// find sentences that contain the word "apple"
4str.match(/[^.!?]*\bapple\b[^.!?]*.?/gi);
5// => ["The apple tree originated in Central Asia.", "Apple matures in late summer or autumn."]
این ریجکس را به صورت گام به گام بررسی میکنیم:
- [!?.^] با هر کاراکتری که یک نقطه (.) یا علامت تعجب (!) یا علامت سوال (?) نباشد تطبیق مییابد.
- * با دنبالهای به طول صفر یا چند کاراکتر از آیتم پشت سر هم تطبیق مییابد.
- b\ با موقعیتی که به نام «کران واژه» (word boundary) شناخته میشود تطبیق مییابد. پس از این موقعیت یا یک حرف ASCII یا یک رقم و یا کاراکتر «زیرخط» (_) میآید.
- Apple با کاراکترهای به صورت لفظی تطبیق مییابد. از آنجا که حساس به کوچکی و بزرگی حروف است فلگ i را به انتهای ریجکس اضافه میکنیم.
- [!?.^] با هر کاراکتری که. یا! یا? نباشد، تطبیق مییابد.
- * با دنبالهای به طول صفر یا چند کاراکتر از آیتم پشت سر هم تطبیق مییابد.
- . با هر کاراکتری که یک کاراکتر شکستن خط نداشته باشد تطبیق مییابد.
- ? با تعداد رخداد صفر یا چند آیتم قبلی تطبیق مییابد.
- g به موتور ریجکس اعلام میکند که با همه رخدادها حتی پس از توقف در نخستین تطبیق مطابقت پیدا کند.
- i موجب میشود جستجو حساس به کوچکی/بزرگی حروف باشد.
جدا کردن کاراکترهای غیرمجاز از نام فایلها
زمانی که یک فایل برای دانلود عرضه میشود، نباید کاراکترهای خاصی را در نام خود داشته باشد. برای نمونه در سیستم عامل ویندوز، کاراکترهای زیر در نام فایلها غیرمجاز هستند و باید از آنها جدا شوند:
- علامت کمتر از (>)
- علامت بیشتر از (<)
- دونقطه (:)
- گیومه (")
- اسلش (/)
- بکاسلش (\)
- خط عمودی (|)
- علامت سؤال (؟)
- ستاره (*)
با استفاده از ریجکس میتوانیم کاراکترهای غیرمجاز را به سادگی جدا کنیم. به مثال زیر توجه کنید:
1const str = "https://en.wikipedia.org/";
2str.replace(/[<>|:"*?\\/]+/g, ''); // => "httpsen.wikipedia.org"
[] یک کاراکتر کلاس نامیده میشود و یکی از کاراکترهای بین براکتها تطبیق مییابد. بنابراین با قرار دادن کاراکترهای غیرمجاز درون آن و افزودن فلگ سراسری (g) در انتهای عبارت منظم، میتوانیم عملاً آن کاراکترها را از رشته جدا کنیم.
توجه داشته باشید که در کلاس کاراکتر، بکاسلش دارای معنای خاصی است و باید با بکاسلش دیگری escape شود (\\). عملگر + کلاس کاراکتر را تکرار میکند به طوری که یک دنباله از کاراکترهای غیرمجاز به صورت همزمان جایگزین میشود. این وضعیت موجب بهبود عملکرد میشود. میتوانید بدون تأثیری بر نتیجه آن را نادیده بگیرید.
به خاطر داشته باشید که آرگومان دوم متد ()replace باید یک رشته خالی باشد، مگر این که بخواهید کاراکتر غیرمجاز را با کاراکتر دیگری جایگزین کنید. چند نام رزرو شده نیز وجود دارند که از سوی ویندوز به صورت داخلی برای وظایف مختلف استفاده میشوند و امکان استفاده از آنها برای نامگذاری فایلها وجود ندارد. نامهای رزرو شده شامل موارد زیر هستند:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9
برای جدا کردن نامهای رزرو شده میتوانید به صورت زیر عمل کنید:
1str.replace(/^(CON|PRN|AUX|NUL|COM1|COM2|COM3|COM4|COM5|COM6|COM7|COM8|COM9|LPT1|LPT2|LPT3|LPT4|LPT5|LPT6|LPT7|LPT8|LPT9)$/i, 'file');
این کد اساساً به موتور ریجکس اعلام میکند که کاراکترهای موجود در رشته str را در صورتی که یکی از کلمههای جداشده با کاراکتر | باشند جدا کند. در این حالت نمیتوانیم از رشته خالی به عنوان آرگومان دوم استفاده کنیم زیرا فایل بدون نام میماند.
توجه کنید که اگر رشته شامل هر کاراکتر اضافی باشد، جایگزین نخواهد شد. برای نمونه con جایگزین میشود، اما concord یک نام فایل معتبر است. این وضعیت با استفاده از ^ و $ در ریجکس اصل آمده است. ^ با ابتدای رشته مطابقت مییابد. بدین ترتیب مطمئن میشویم که کاراکترهای دیگری پیش از مورد جستجو در رشته نیامده است. $ نیز با انتهای رشته تطبیق مییابد.
همچنین میتوانیم ریجکسی بنویسیم که به روشی فشردهتر از یک کلاس کاراکتر استفاده کند:
1str.replace(/^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i, 'file');
[1-9] با یک رقم بین 1 تا 9 تطبیق مییابد.
جایگزینی چندین کاراکتر فاصله با یک کاراکتر فاصله
زمانی که یک صفحه وب رندر میشود، کاراکترهای فاصله متعدد به صورت یک کاراکتر فاصله منفرد رندر میشوند. با این حال گاهی اوقات لازم است که ورودی کاربر یا دادههای دیگر را طوری پاکسازی کنیم که کاراکترهای فاصله پشت سر هم با یک کاراکتر فاصله منفرد جایگزین شوند.
طرز کار آن در ریجکس به صورت زیر است:
1const str = " My opinions may have changed, but not the fact that I'm right."; // Ashleigh Brilliant
2str.replace(/\s\s+/g, ' ');
3// => " My opinions may have changed, but not the fact that I'm right."
این ریجکس تنها شامل دو متاکاراکتر، یک عملگر و یک فلگ است:
- s\ با یک کاراکتر فاصله منفرد تطبیق مییابد که شامل فاصله ASCII ،tab ،line feed ،carriage return ،vertical tab و form feed است.
- s\ دوباره با یک کاراکتر فاصله منفرد تطبیق مییابد.
- + با آیتم قبلی یک یا چند بار تطبیق مییابد.
- g به موتور ریجکس اعلام میکند که همه رخدادها علیرغم توقف در نخستین مطابقت پیدا شوند.
نتیجه کار این است که همه کاراکترهای فاصله که دستکم دو بار تکرار شدهاند حذف میشوند. توجه کنید که در نتیجه مثال فوق همچنان یک کاراکتر فاصله در ابتدا وجود دارد که باید حذف شود. به این منظور کافی است تابع ()trim را به انتهای گزاره اضافه کنیم:
1str.replace(/\s\s+/g, ' ').trim();
2// => "My opinions may have changed, but not the fact that I'm right."
به خاطر بسپارید که این کد هر نوع کاراکتر فاصله را که شامل فاصله ASCII ،tab ،line feed ،carriage return ،vertical tab و form feed میشود با یک کاراکتر فاصله (U+0020) جایگزین میکند. بنابراین اگر یک کاراکتر carriage return بیدرنگ پس از tab آمده باشد، با یک فاصله جایگزین میشوند. اگر چنین مقصودی ندارید، و تنها میخواهید کاراکترهای فاصله از یک نوع را با استفاده از کد حذف کنید به روش زیر عمل کنید:
1str.replace(/(\s)\1+/g, '$1').trim();
1\ یک ارجاع به عقب است و با همان کاراکتری تطبیق مییابد که در جفت اول پرانتزها (s\) تطبیق یافته است. برای جایگزینی آنها از 1$ در آرگومان دوم ()replace استفاده میکنیم که کاراکتری را درج کند که در پرانتز تطبیق یافته است.
محدودسازی ورودی کاربر به کاراکترهای حرفی/عددی
یکی از وظایف رایج در زمان توسعه وب این است که ورودی کاربر را صرفاً به کاراکترهای حرفی/عددی محدود کنیم. با استفاده از عبارتهای منظم دستیابی به این وظیفه کاری بسیار ساده است. از یک کلاس کاراکتر برای تعریف کردن محدوده مجاز کاراکترها استفاده میکنیم و سپس یک «کمّیساز» (quantifier) به آن اضافه میکنیم تا تعداد دفعاتی که کاراکتر میتواند تکرار شود را تعیین کنیم:
1const input1 = "John543";
2const input2 = ":-)";
3/^[A-Z0-9]+$/i.test(input1); // → true
4/^[A-Z0-9]+$/i.test(input2); // → false
نکته: این ریجکس تنها برای زبان انگلیسی مفید است و با حرف یا حروف از زبانهای دیگر تطبیق نمییابد.
طرز کار آن به صورت زیر است:
- ^ با ابتدای رشته تطبیق مییابد. بدین ترتیب مطمئن میشویم که هیچ کاراکتر دیگری پیش از رشتهای که میخواهیم تطبیق پیدا کند، نیامده است.
- [A-Z0–9] با یک کاراکتر بین A تا Z و بین 0 تا 9 تطبیق پیدا میکند. از آنجا که به کوچکی/بزرگی حروف حساس است یک فلگ i به انتهای ریجکس اضافه میکنیم. به طور جایگزین میتوانیم از [A-Za-z0–9] بدون فلگ استفاده کنیم.
- + با یک یا چند آیتم قبلی تطبیق مییابد. بنابراین ورودی باید دستکم یک کاراکتر حرفی-عددی به جز کاراکتر فاصله داشته باشد؛ در غیر این صورت تطبیق صورت نمیگیرد. اگر میخواهید این فیلد اختیاری باشد میتوانید از کمی ساز * استفاده کنید که با صفر یا چند آیتم قبلی تطبیق مییابد.
- $ با انتهای رشته تطبیق مییابد.
تبدیل URL-ها به لینک
فرض کنید میخواهید یک یا چند URL را به یک متن تبدیل کنید که عنصر anchor در HTML نیستند و از این رو قابل کلیک نیستند. میخواهیم URL-ها را به صورت خودکار به لینکهایی تبدیل کنیم. به این منظور ابتدا باید URL-ها را پیدا کنیم و سپس هر یک را درون تگهای <a>…</a> قرار دهیم که دارای خصوصیت href است که به URL اشاره میکند:
1const str = "Visit https://en.wikipedia.org/ for more info.";
2str.replace(/\b(https?|ftp|file):\/\/\S+[\/\w]/g, '<a href="$&">$&</a>');
3// => "Visit <a href="https://en.wikipedia.org/">https://en.wikipedia.org/</a> for more info."
نکته: در زمان استفاده از ریجکس مراقب باشید، زیرا با URL-هایی که به یک علامت تعجب خاتمه یافتهاند تطبیق نمییابد. همچنین ممکن است با URL-های پیچیدهتر تطبیق نیابد.
طرز کار کد فوق به صورت زیر است:
- b\ با موقعیتی تطبیق مییابد که به نام «کران واژه» شناخته میشود.
- (https?|ftp|file) با کاراکترهای https یا http یا ftp و یا file تطبیق مییابد.
- : با خود کاراکتر دونقطه تطبیق مییابد.
- s\ با هر کاراکتر منفردی که کاراکتر فاصله نباشد تطبیق مییابد.
- + یک یا چند بار آیتم قبلی تطبیق مییابد.
- [\/\w] با یک اسلش یا یک کاراکتر کلمه تطبیق مییابد. اگر از این بخش استفاده نکنیم، ریجکس با هر علامت تعجب در انتهای URL تطبیق مییابد.
- g به موتور ریجکس اعلام میکند که همه رخدادها را به جای توقف پس از نخستین تطبیق، پیدا کند.
- &$ در آرگومان دوم متد ()replace زیررشته تطبیق یافته را درون رشته جایگزینی قرار میدهد.
حذف کلمات تکراری
این که در مقالات و راهنماهای مختلف کلماتی به صورت ناخواسته درج شده باشند، امر نامتداولی محسوب نمیشود. حتی نویسندگان حرفهای نیز باید نوشتههای خود را بازخوانی کنند تا از بروز چنین خطاهایی جلوگیری به عمل آورند. با یک جستجوی ساده مانند گشتن به دنبال “the the” در بخش اخبار گوگل میبینیم که صدها خبرگزاری مهم در مقالات خود مرتکب چنین اشتباهی در مورد کلمات تکراری شدهاند. خوشبختانه عبارتهای منظم به ما امکان میدهند که این مشکل را با یک خط کد حل کنیم:
1const str = "This this sentence has has double words.";
2str.replace(/\b(\w+)\s+\1\b/gi, '$1');
3// => "This sentence has double words."
- b\ با موقعیت «کران واژه» تطبیق مییابد. در این موقعیت یک حرف ASCII یا یک رقم و یا زیرخط در ادامه میآید یا قبل از آن آمده است.
- w\ با یک کاراکتر کلمه تطبیق مییابد.
- + با یک یا چند آیتم قبل تطبیق مییابد.
- s\ با یک کاراکتر فاصله تطبیق مییابد.
- + با یک یا چند آیتم قبلی تطبیق مییابد به طوری که کلمههای تکراری با یک کاراکتر فاصله در بینشان تشخیص داده میشوند.
- 1\ یک کاراکتر اسلش است و با همان متنی تطبیق می یابد که در نخستین پرانتز آمده است.
- b\ با یک کران واژه تطبیق مییابد.
- g به موتور ریجکس اعلام میکند که همه رخدادها را علیرغم توقف پس از نخستین تطبیق پیدا کند.
- i موجب میشود که جستجو به کوچکی/ بزرگی حروف حساس شود.
- 1$ در آرگومان دوم متد ()replace موجب میشود متنی که در پرانتز اول آمده درج شود.
سخن پایانی
عبارتهای منظم به بخش مهمی از مجموعه ابزارهای هر برنامهنویسی تبدیل شدهاند. در این مقاله به بررسی این نکته پرداختیم که توسعهدهندگان فرانتاند چگونه میتوانند از مزیت عبارتهای منظم برای اجرای وظایف مختلف بهرهمند شوند. توجه داشته باشید که ما در این مقاله صرفاً گوشه کوچکی از قدرت عبارتهای منظم را بررسی کردیم، برای آشنای بیشتر با این ابزار مهم توصیه میکنیم در این خصوص بیشتر مطالعه کنید از جمله میتوانید از لینکهای زیر استفاده کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- آموزش جاوا اسکریپت (JavaScript)
- راهنمای سریع Regex — فهرست کاربردی
- عبارتهای منظم (RegEx) در جاوا اسکریپت — به زبان ساده
==