۳ ریجکس مفید برای توسعه دهندگان وب | به زبان ساده

۲۹۷ بازدید
آخرین به‌روزرسانی: ۱۳ شهریور ۱۴۰۲
زمان مطالعه: ۷ دقیقه
۳ ریجکس مفید برای توسعه دهندگان وب | به زبان ساده

ما در مجله فرادرس پیش‌تر مقالات متعددی در مورد اهمیت و ماهیت ریجکس (Regex) به رشته تحریر درآورده‌ایم و کاربردهای آن را نیز با ارائه راهنماهای عملی مختلف بیان کرده‌ایم. اما هر چه از اهمیت ریجکس گفته شود، کم است. در این مقاله به بررسی 3 ریجکس مفید برای توسعه‌دهندگان وب می‌پردازیم.

قبل از هر چیز باید توضیح بدهیم که همه مثال‌های مطرح شده در این راهنما با استفاده ابزار آنلاین regexr (+) تست شده‌اند. همچنین بهتر است آشنایی قبلی با موارد زیر داشته باشید:

  • تعیین موقعیت ریجکس مانند ^ و $
  • مجموعه کاراکترها مانند [a-z] و [A-Z]
  • تعیین کمیت مانند *، + و?
  • جایگزینی مانند {5} و {2,} {1,3}
  • گروه‌ها مانند s (?=abc)
  • تغییراتی مانند ab | cd

با ما همراه باشید تا با 3 ریجکس مهم برای توسعه‌دهندگان وب آشنا شوید.

ریجکس تائید ایمیل

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

کدهای آن را نیز در ادامه آورده‌ایم.

([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})*$

کاربرد این ریجکس در کد به صورت زیر است:

1const regex = new RegExp('^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})*$');
2
3const test1 = 'glipmsum_1%-@gmail.com';
4const test2 = '12glipms12um_1%-@outlook.com';
5const test3 = '12glipms12um_1%-@gmail.co.ca';
6const test4 = '12glipms12um_1%-@gmail';
7const test5 = '12glipms12um_1%-@gmail.e';
8const test6 = '12glipms12um_1%-@gmail.edu.';
9
10console.log(regex.test(test1)); // true
11console.log(regex.test(test2)); // true
12console.log(regex.test(test3)); // true
13console.log(regex.test(test4)); // false
14console.log(regex.test(test5)); // false
15console.log(regex.test(test6)); // false

توضیح

در این ریجکس از دو کاراکتر anchor به صورت زیر استفاده شده است:

  • علامت ^ برای نشان دادن ابتدای رشته.
  • علامت $ برای نشان دادن موقعیت انتهای رشته.

برای تفهیم بیشتر به مثال زیر توجه کنید:

1console.log(new RegExp('^abc$').test('abc')); // true
2console.log(new RegExp('^abc$').test('Abc')); // false
3
4// i : case insensitive
5// /^abc$/i/
6console.log(new RegExp('^abc$', 'i').test('Abc')); // true

دیکشنری

  • مجموعه کاراکتر [a-zA-Z0-9._%-] – در ریجکس فوق استفاده شده است که a-z با مجموعه کاراکترهای الفبایی از a تا z تطبیق می‌یابد و به کوچکی/بزرگی حروف حساس است. همچنین A-Z با کاراکترهای الفبایی از A تا Z تطبیق می‌یابد که باز حساس به کوچکی/بزرگی حروف است.
  • در ادامه 0-9 آمده است که با ارقام 0 تا 9 تطبیق پیدا می‌کند.
  • سپس کاراکتر (.) را می‌بینیم که با همان کاراکتر نقطه تطبیق پیدا می‌کند.
  • در ادامه کاراکتر زیرخط (_) را شاهد هستیم که با خود این کاراکتر در رشته تطبیق پیدا می‌کند.
  • کاراکتر % نیز با خود کاراکتر تطبیق می‌یابد.
  • همچنین کاراکتر خط تیره (-) با خود کاراکتر تطبیق می‌یابد.

در مورد مجموعه کاراکترها باید به حالت‌های زیر توجه کنید:

  • [abc] – با هر یک از حروف a، b یا c تطبیق می‌یابد.
  • [^abc] – با هر یک از حالت‌هایی که شامل a، b یا c نباشد تطبیق می‌یابد.
  • [a-g] – با کاراکترهای بین a تا g تطبیق می‌یابد.

به مثال زیر توجه کنید:

1const regex = new RegExp('[abc]');
2
3const test1 = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry';
4console.log(regex.test(test1)); // true (1 match) because there's "a" in "and"
5//
6//
7const regex = new RegExp('[^abc]');
8
9const test1 = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry';
10console.log(regex.test(test1)); // true (72 matches) every characters except for "a" in "and"
11//
12//
13const regex = new RegExp('[a-g]');
14
15const test1 = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry';
16console.log(regex.test(test1)); // true (12 matches) 12 matches for character "a","b","c","d","e","f","g"
17//
18//
19
20const regex = new RegExp('[^a-g]');
21
22const test1 = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry';
23console.log(regex.test(test1)); // true (61 matches) 61 matches for character NOT "a","b","c","d","e","f","g"

در ادامه ریجکس‌های کمیت‌ساز را بررسی می‌کنیم. در ریجکس فوق شاهد [a-zA-Z0-9._%-]+ هستیم.

  • *a - نشانگر 0 یا چند مورد از توکن قبل خود است.
  • -a - نشانگر 1 یا چند مورد از توکن قبل خود است.

به مثال زیر توجه کنید:

1const regex = new RegExp('^(a*b*d*c*)$');
2
3const test1 = 'aaaacccc';
4const test2 = 'aaaabbddcccc';
5const test3 = 'aaaabbcc';
6const test4 = 'bbddcccc';
7const test5 = 'cccc';
8
9console.log(regex.test(test1)); // true
10console.log(regex.test(test2)); // true
11console.log(regex.test(test3)); // true
12console.log(regex.test(test4)); // true
13console.log(regex.test(test5)); // true
14//
15//
16const regex_plus = new RegExp('^(a+b+d+c+)$');
17console.log(regex_plus.test(test1)); // false
18console.log(regex_plus.test(test2)); // true
19console.log(regex_plus.test(test3)); // false
20console.log(regex_plus.test(test4)); // false
21console.log(regex_plus.test(test5)); // false

در این بخش ریجکس‌های مرتبط با جایگزینی را بررسی می‌کنیم. در ریجکس فوق شاهد توکنی به صورت a-zA-Z]{2,6} هستیم که توضیحات آن به صورت زیر است:

  • a{5} – دقیقاً با 5 بار تطبیق می‌یابد.
  • a{2,} – با 2 مورد یا بیشتر تطبیق می‌یابد.
  • a{1,3} – بین 1 تا 3 بار تطبیق می‌یابد.

به مثال زیر توجه کنید:

1const regex = new RegExp('a{5}');
2
3const test1 = 'aaaaa';
4const test2 = 'a';
5
6console.log(regex.test(test1)); // true
7console.log(regex.test(test2)); // false
8//
9//
10const regex = new RegExp('a{3,}');
11
12const test1 = 'aa';
13const test2 = 'aaaa';
14
15console.log(regex.test(test1)); // false
16console.log(regex.test(test2)); // true
17//
18//
19const regex = new RegExp('a{3,5}');
20
21const test1 = 'aa';
22const test2 = 'aaaa';
23const test3 = 'aaaaa';
24
25console.log(regex.test(test1)); // false
26console.log(regex.test(test2)); // true
27console.log(regex.test(test3)); // true

موارد دشوار

توجه کنید که برخی نشانی‌های ایمیل نادرست پیچیده وجود دارند که ممکن است از سد اعتبارسنجی ریجکس فوق رد شوند. به مثال زیر توجه کنید:

12glipms12um_1%-@gmail.edu.df12glipms12um_1%-@gmail.edu

این مثال همان طور که در کد زیر می‌بینید از سد ریجکس اعتبارسنجی قبلی عبور می‌کند:

const regex = new RegExp('^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\. [a-zA-Z]{2,6})*$')
1const regex = new RegExp('^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})*$');
2
3const test1 = '12glipms12um_1%-@gmail.edu.df12glipms12um_1%-@gmail.edu';
4const test2 = '12glipms12um_1%-@gmail.eduwerdsf';
5// const test3 = 'aaaaa';
6
7console.log(regex.test(test1)); // true
8console.log(regex.test(test2)); // false because it execeeds 6 letters after "."

ریجکس اعتبارسنجی پیشرفته ایمیل

برای این که بتوانیم نقیصه ریجکس قبلی را برطرف کنیم باید از یک کمیت‌ساز (Quantifier) پیشرفته به صورت زیر استفاده کنیم:

a?- 0 یا 1

بدین ترتیب در صورتی که گروه () بیش از یک بار آمده باشد، این رشته از تست ما موفق بیرون نمی‌آید:

1const regex = new RegExp('^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})?$');
2
3const test1 = '12glipms12um_1%-@gmail.edu.df12glipms12um_1%-@gmail.edu';
4
5console.log(regex.test(test1)); // false

3 ریجکس مفید برای توسعه دهندگان وب

پیچیدگی رمز عبور

در این بخش یک ریجکس مفید دیگر را برای توسعه‌دهندگان فرانت‌اند معرفی می‌کنیم. این ریجکس میزان پیچیدگی و قدرت یک رمز عبور را بررسی می‌کند:

(?=(.*[0-9]))(?=.*[!@#$%^&*()-_+=~`|:;\"'<>,./?])(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{8,}

پیش از آن که به توضیح اجزای این ریجکس بپردازیم، باید اشاره کنیم که این ریجکس شامل تعداد زیادی «اطراف‌نگری» مثبت بودن به شکل?=(..) است. تعداد زیادی اطراف‌نگری‌های مثبت و منفی وجود دارند که استفاده از هردوی آن‌ها در حالتی که موقعیت حروف ثابت نباشد، مفید خواهد بود.

دیکشنری

توجه کنید که در مثال ریجکس قبلی برای اعتبارسنجی نشانی ایمیل ما موقعیت حروف را می‌دانستیم:

<email User Name> @ <email Provider>. <extension>

با این حال موقعیت حروف در رمزهای عبور ثابت نیست. به مثال‌های زیر توجه کنید:

Gwl213ed!@
skwenfklEq!@!12

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

1const regex = new RegExp("(?=(.*[0-9]))(?=.*[!@#$%^&*()-_+=~`|:;\"'<>,./?])(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{8,}");
2
3const test1 = 'HFNwdvwe513!';
4const test2 = 'GGWNWND123!@@@!';
5const test3 = 'GGWNWNmdD123!@@@!';
6const test4 = 'GW1e!!';
7
8
9console.log(regex.test(test1)); // true
10console.log(regex.test(test2)); // false NO lowercase letter
11console.log(regex.test(test3)); // true
12console.log(regex.test(test4)); // false Less than 8 letters

گروه‌ها و پیش‌نگری مثبت

  • (abc) – به دست آوردن گروه
  • (?=abc) – بررسی مثبت بودن.

گروه‌ها

به دست آوردن گروه‌ها: گروه‌ها ترکیبی از چند توکن هستند و ایجاد یک کپچر گروه برای استخراج زیررشته یا استفاده از ارجاع به قبل استفاده می‌شود:

1const regex = new RegExp('^(abc)$');
2
3const test1 = 'abc';
4const test2 = 'abcd'
5
6
7console.log(regex.test(test1)); // true
8console.log(regex.test(test2)); // false
9//
10//
11const regex = new RegExp('^(ab*c)$');
12
13const test1 = 'abc';
14const test2 = 'ac'
15
16
17console.log(regex.test(test1)); // true
18console.log(regex.test(test2)); // true // * quantifier is for 0 or more

پیش‌نگری مثبت

در «پیش‌نگری مثبت» (Positive lookahead) یک گروه پس از عبارت اصلی بدون این که در نتیجه جای بگیرد، تطبیق می‌یابد. ساختار کار به صورت X(?=Y) است یعنی «به دنبال X بگرد، اما تنها در صورتی آن را تطبیق بده که پس از Y آمده باشد» یا به عبارت دیگر:

X(?=Y)(?=Z)
  1. X را پیدا کن.
  2. بررسی کن آیا Y درست پس از X آمده باشد (اگر چنین نبود، رد شو)
  3. بررسی کن آیا Z نیز دقیقاً پس از X آمده است (اگر چنین نبود، رد شو)
  4. اگر هر دو تست پاس شد، در این صورت X تطبیق یافته، در غیر این صورت به جستجو ادامه بده.

به مثال زیر توجه کنید:

1const regex = new RegExp('(?=(.*[0-9])).');
2
3const test1 = 'helloworld';
4const test2 = 'helloworld1';
5const test3 = '123';
6
7
8console.log(regex.test(test1)); // false No number (0 - 9)
9console.log(regex.test(test2)); // true
10console.log(regex.test(test3)); // true

توجه کنید که خواندن از انتها سریع‌تر است. در ریجکس زیر نقطه (.) با هر کاراکتری به جز کاراکتر line break تطبیق پیدا می‌کند. با این فرض در رشته hel\nlo\n1 کاراکتر نقطه با شش کاراکتر عبارت به جز شکستگی خطوط تطبیق می‌یابد.

بدین ترتیب ریجکس فوق با هر عبارت کاراکتری (0 یا چند کاراکتر) که پس از آن عدد آمده باشد تطبیق می‌یابد و لذا helloworld1 و 123 تطبیق پیدا می‌کنند.

به عبارت دیگر می‌توانیم ریجکس زیر را به چند «اطراف‌نگری مثبت» (positive lookaround) تجزیه کنیم:

(?=(.*[0-9]))(?=.*[!@#$%^&*()-_+=~`|:;\"'<>,./?])(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{8,}

نتیجه کار به صورت زیر است:

(?=(.*[0-9])): looks for numbers
(?=.*[!@#$%^&*()-_+=~`|:;\"'<>,./?]): looks for special characters
(?=.*[a-z]): looks for lowercase letters
(?=(.*[A-Z])): looks for upper case letters
(?=(.*)): looks for everything

چنان که می‌بینید 5 گروه از اطراف‌نگری مثبت به صورت حریصانه (greedily) به دنبال تطبیق‌های خود می‌گردند و تست ریجکس تنها در صورتی پاس می‌شود که همه معیارها تطبیق یابند.

در نهایت باید اشاره کنیم که در ریجکس فوق، در بخش.{8,} کاراکتر (0) تنها ریجکس خارج از اطراف‌نگری مثبت است و در واقع نقطه شروع واقعی ریجکس محسوب می‌شود. این توکن به دنبال هر کاراکتری به جز کاراکتر newline می‌گردد.

همچنین {8,} یک جایگزینی است که نماینده 8 حرف یا بیشتر است.

تاریخ‌ در قالب YYYY-MM-dd

سومین و آخرین ریجکسی که در این مقاله معرفی می‌کنیم و برای توسعه‌دهندگان فرانت‌اند مفید و مهم است به صورت زیر است:

([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))

ریجکس فوق برای regexr نوشته شده است، اما برای این که در جاوا اسکریپت کار کند باید یک \ اضافی در ابتدای `\d` اضافه کنید، زیرا از آن به صورت یک رشته در RegExp در جاوا اسکریپت استفاده می‌کنیم:

([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))

به مثال زیر توجه کنید:

1const regex = new RegExp('([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))');
2
3const test1 = '1992-12-01';
4const test2 = '2020-10-10';
5const test3 = '3010-12-22';
6const test4 = '2020-21-10';
7const test5 = '3010-12-35';
8
9
10console.log(regex.test(test1)); // true
11console.log(regex.test(test2)); // true
12console.log(regex.test(test3)); // false
13console.log(regex.test(test4)); // false
14console.log(regex.test(test5)); // false

دیکشنری

ابتدا شاهد یک توکن جایگزین به شکل ab | cd هستیم که با ab یا cd تطبیق می‌یابد. بنابراین ریجکس زیر را می‌توان به سه بخش تجزیه کرد که با \ از هم جدا شده‌اند:

([12]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]))

نتیجه تجزیه به صورت زیر است:

([12]\\d{3}-
(0[1-9]|1[0-2])-
(0[1-9]|[12]\\d|3[01]))

این ریجکس شبیه یک دسته از گزا‌ره‌های if است.

  • در بخش اول شاهد توکن ([12]\\d{3} هستیم که مشخص می‌سازد حرف اول باید یکی از ارقام 1 یا 2 باشد [12] و سپس در ادامه باید سه رقم آمده باشد \\d{3}.
  • در گزاره if دوم شاهد (0[1-9]|1[0-2]) هستیم که مشخص می‌کند این عبارت باید با 0 و یا 1 آغاز شود. اگر با 0 آغاز شود رقم بعدی باید درباره 1 تا 9 باشد، اما گر با 1 آغاز شود، در این صورت رقم بعدی باید در بازه 0 تا 2 باشد.
  • گزاره if سوم به صورت (0[1-9]|[12]\\d|3[01])) است که مشخص می‌سازد عبارت باید با 0 آغاز شود یا با 1 یا 2 آغاز شود و یا با 3 آغاز شود.
  • اگر عبارت با 0 آغاز شود، رقم بعدی باید در بازه 1 تا 9 باشد.
  • اگر با 1 یا 2 آغاز شود، رقم بعدی می‌تواند هر رقمی `\d` [0-9] باشد.
  • اگر با 3 آغاز شود، رقم بعدی باید 0 یا 1 باشد.

به این ترتیب به انتهای این مقاله می‌رسیم. امیدواریم این راهنمای کاربردی با عنوان 3 ریجکس مفید برای توسعه‌دهندگان وب مورد توجه شما قرار گرفته باشد.

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
javascript-in-plain-english
۱ دیدگاه برای «۳ ریجکس مفید برای توسعه دهندگان وب | به زبان ساده»

سلام
عبارات با قاعده
در این خط کد بجای جایگزینی یک غلط میخواهم تمام کلماتی که در یک جمله غلط نوشته شده را اصلاح کنم اما در replaceفقط امکان تغییر یک کلمه وجود دارد .راه حل چیست؟let x=text.replace(“fisnsh”,”in”) مثلا
البته از روشهای دیگر نمی خواهم استفاده کنم.fisnshکلمه غلط است .finish صحیح آنست

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *