مسیرها
/
Elixir
Elixir
/
تمرین‌ها
/
تجزیه‌گر تاریخ
تجزیه‌گر تاریخ

تجزیه‌گر تاریخ

تمرین یادگیری

مقدمه

عبارت‌های باقاعده

عبارات باقاعده (رجکس) ابزاری قدرتمند برای کار با رشته‌ها در Elixir هستند. عبارت‌های باقاعده در Elixir از مشخصات PCRE (Perl Compatible Regular Expressions) پیروی می‌کنند. الگوهای رشته‌ای که معنای عبارت باقاعده را نشان می‌دهند، ابتدا کامپایل می‌شوند و سپس برای تطبیق دادن همه یا بخشی از یک رشته به کار می‌روند.

در Elixir، رایج‌ترین راه ساختن عبارت باقاعده استفاده از سیجیل ~r است. سیجیل‌ها «شکر نحوی» هستند، یعنی میان‌برهایی برای کارهای رایج در Elixir. برای تطبیق یک «رشته‌ی تحت‌اللفظی»، می‌توانیم خودِ رشته را به‌عنوان الگویی که بعد از سیجیل می‌آید به کار ببریم.

~r/test/

عملگر =~/2 برای انجام یک تطبیق رجکس روی یک رشته و برگرداندن نتیجه‌ی boolean به کار می‌رود.

"this is a test" =~ ~r/test/
# => true

دو نکته درباره‌ی استفاده از سیجیل‌ها:

  • بسته به نیازتان می‌توانید به‌جای / از جداکننده‌های مختلفی استفاده کنید
  • الگوهای رشته‌ای از قبل گریز داده شده‌اند؛ وقتی الگو را به‌صورت رشته می‌نویسید و از عبارت باقاعده استفاده نمی‌کنید، باید به بک‌اسلش‌ها (\) گریز بدهید

کلاس‌های نویسه

تطبیق دادن یک بازه از نویسه‌ها با براکت‌های مربعی [] یک «کلاس نویسه» را تعریف می‌کند. این هر یک نویسه را با نویسه‌های موجود در کلاس مطابقت می‌دهد. همچنین می‌توانید بازه‌ای از نویسه‌ها مانند a-z را مشخص کنید، به شرطی که ابتدا و انتهای آن بازه‌ای پیوسته از نقطه‌های کد را نشان دهند.

regex = ~r/[a-z][ADKZ][0-9][!?]/
"jZ5!" =~ regex
# => true
"jB5?" =~ regex
# => false

«کلاس‌های نویسه‌ی کوتاه‌نویسی‌شده» الگو را مختصرتر می‌کنند. برای مثال:

  • \d کوتاه‌شده‌ی [0-9] (هر رقم)
  • \w کوتاه‌شده‌ی [A-Za-z0-9_] (هر نویسه‌ی «واژه»)
  • \s کوتاه‌شده‌ی [ \t\r\n\f] (هر نویسه‌ی فاصله)

وقتی یک «کلاس نویسه‌ی کوتاه‌نویسی‌شده» بیرون از سیجیل به کار می‌رود، باید گریز داده شود: "\\d"

جانشینی

«جانشینی» از | به‌عنوان نویسه‌ای ویژه استفاده می‌کند تا نشان دهد یکی یا دیگری مطابقت داده می‌شود.

regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true

کمیت‌سنج‌ها

«کمیت‌سنج‌ها» امکان الگویی تکراری در عبارت باقاعده را فراهم می‌کنند. آن‌ها روی گروهی که پیش از کمیت‌سنج می‌آید اثر می‌گذارند.

  • {N, M} که N کمترین تعداد تکرار است و M بیشترین
  • {N,} تطبیق N تکرار یا بیشتر
    • {0,} را می‌توان به‌صورت * هم نوشت: تطبیق صفر تکرار یا بیشتر
    • {1,} را می‌توان به‌صورت + هم نوشت: تطبیق یک تکرار یا بیشتر
  • {,N} تطبیق تا N تکرار

گروه‌ها

پرانتزهای گرد () برای نشان دادن «گروه»ها و «ثبت»ها به کار می‌روند. گاهی هم گروه ثبت می‌شود تا برای استفاده برگردانده شود. در Elixir، این‌ها می‌توانند نام‌دار یا بی‌نام باشند. ثبت‌ها با افزودن ?<name> بعد از پرانتز باز نام‌گذاری می‌شوند. گروه‌ها مانند یک واحد یکپارچه عمل می‌کنند، مثلاً وقتی بعد از آن‌ها کمیت‌سنج می‌آید.

regex = ~r/(h)at/
Regex.replace(regex, "hat", "\\1op")
# => "hop"

regex = ~r/(?<letter_b>b)/
Regex.scan(regex, "blueberry", capture: :all_names)
# => [["b"], ["b"]]

لنگرها

«لنگرها» برای گره زدن عبارت باقاعده به ابتدا یا انتهای رشته‌ای که باید مطابقت داده شود به کار می‌روند:

  • ^ لنگر ابتدای رشته است
  • $ لنگر انتهای رشته است

درون‌گذاری

چون ~r میان‌بری برای "pattern" |> Regex.escape() |> Regex.compile!() است، می‌توانید الگوی عبارت باقاعده را به‌صورت پویا با «درون‌گذاری» رشته هم بسازید:

anchor = "$"
regex = ~r/end of the line#{anchor}/
"end of the line?" =~ regex
# => false
"end of the line" =~ regex
# => true

دستورالعمل‌ها

مأموریت شما نوشتن سرویسی است که رویدادها را دریافت می‌کند. هر رویداد تاریخی دارد، اما متوجه می‌شوید که ۳ قالب مختلف به اندپوینت سرویس شما فرستاده می‌شود:

  • "01/01/1970"
  • "January 1, 1970"
  • "Thursday, January 1, 1970"

می‌بینید که میان آن‌ها شباهت‌هایی وجود دارد و تصمیم می‌گیرید چند الگوی عبارت باقاعده‌ی ترکیب‌پذیر بنویسید.

1. روز، ماه و سال را از یک تاریخ تطبیق دهید

day/0، month/0 و year/0 را طوری پیاده‌سازی کنید که یک الگوی رشته‌ای برگردانند که با کامپایل شدن، اجزای عددی "01/01/1970" را تطبیق دهد (قالب dd/mm/yyyy). روز و ماه ممکن است به شکل 1 یا 01 بیایند (با صفر در سمت چپ پر شده باشند).

"31" =~ DateParser.day() |> Regex.compile!()
# => true
"12" =~ DateParser.month() |> Regex.compile!()
# => true
"1970" =~ DateParser.year() |> Regex.compile!()
# => true

2. روز هفته و ماه سال را تطبیق دهید

day_names/0 و month_names/0 را طوری پیاده‌سازی کنید که یک الگوی رشته‌ای برگردانند که با کامپایل شدن، به‌ترتیب نام روز هفته و نام ماه سال را تطبیق دهد.

"Tuesday" =~ DateParser.day_names() |> Regex.compile!()
# => true
"June" =~ DateParser.month_names() |> Regex.compile!()
# => true

3. روز، ماه و سال را ضبط کنید

capture_day/0، capture_month/0، capture_year/0، capture_day_name/0 و capture_month_name/0 را طوری پیاده‌سازی کنید که یک الگوی رشته‌ای برگردانند که اجزای مربوطه را با این نام‌ها ضبط کند: "day"، "month"، "year"، "day_name"، "month_name"

DateParser.capture_month_name()
|> Regex.compile!()
|> Regex.named_captures("December")

# => %{"month_name" => "December"}

4. ضبط‌ها را ترکیب کنید تا کل تاریخ را ضبط کنید

capture_numeric_date/0، capture_month_name_date() و capture_day_month_name_date/0 را طوری پیاده‌سازی کنید که یک الگوی رشته‌ای برگردانند که اجزای بخش ۳ را با قالب تاریخ مربوطه ضبط کند:

  • تاریخ عددی - "01/01/1970"
  • تاریخ با نام ماه - "January 1, 1970"
  • تاریخ با نام روز و ماه - "Thursday, January 1, 1970"
DateParser.capture_numeric_date()
|> Regex.compile!()
|> Regex.named_captures("01/01/1970")

# => %{"day" => "01", "month" => "01", "year" => "1970"}

5. ضبط را محدود کنید تا فقط با تاریخ تطبیق داده شود

match_numeric_date/0، match_month_name_date/0 و match_day_month_name_date/0 را طوری پیاده‌سازی کنید که یک عبارت باقاعده‌ی کامپایل‌شده برگردانند که فقط با تاریخ تطبیق داده شود و بتواند اجزا را هم ضبط کند.

"Thursday, January 1, 1970 was the Unix epoch." =~ DateParser.match_day_month_name_date()
# => false
"Thursday, January 1, 1970" =~ DateParser.match_day_month_name_date()
# => true

DateParser.match_day_month_name_date()
|> Regex.named_captures("Thursday, January 1, 1970")

# => %{
#     "day" => "1",
#     "day_name" => "Thursday",
#     "month_name" => "January",
#     "year" => "1970"
#   }
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Elixir Exercism

آماده‌اید تجزیه‌گر تاریخ را شروع کنید؟

در Exercism ثبت‌نام کنید تا Elixir را همراه با 58 مفهوم168 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.