Kurzusok
/
Elixir
Elixir
/
Feladatok
/
Dátumelemző
Dátumelemző

Dátumelemző

Tanulófeladat

Bevezetés

Reguláris kifejezések

A reguláris kifejezések (regex) hatékony eszközt jelentenek, ha Elixirben stringekkel dolgozunk. Az Elixirben a reguláris kifejezések a PCRE specifikációt követik (Perl Compatible Regular Expressions). A reguláris kifejezés jelentését leíró string-mintákat először lefordítjuk, majd a string egészének vagy egy részének illesztésére használjuk.

Az Elixirben a reguláris kifejezések létrehozásának leggyakoribb módja a ~r sigil használata. A sigilek szintaktikai cukor rövidítéseket kínálnak az Elixirben gyakori feladatokhoz. Egy string literál illesztéséhez magát a stringet használhatjuk mintaként a sigil után.

~r/test/

A =~/2 operátorral reguláris kifejezést illeszthetsz egy stringre, és boolean eredményt kapsz.

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

Két megjegyzés a sigilek használatához:

  • az igényeidtől függően sokféle elválasztó karaktert használhatsz a / helyett
  • a string-minták már escape-elve vannak; ha a mintát regex helyett stringként írod le, akkor magadnak kell escape-elned a fordított perjeleket (\)

Karakterosztályok

A karakterek egy tartományának szögletes zárójellel ([]) való illesztése egy karakterosztályt definiál. Ez az osztályban szereplő karakterek bármelyikére illeszkedik. Megadhatsz karaktertartományt is, például a-z, feltéve hogy a kezdő és a záró karakter összefüggő kódponttartományt jelöl.

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

A rövidített karakterosztályok tömörebbé teszik a mintát. Például:

  • \d a [0-9] rövidítése (bármely számjegy)
  • \w az [A-Za-z0-9_] rövidítése (bármely „szó” karakter)
  • \s a [ \t\r\n\f] rövidítése (bármely whitespace karakter)

Ha egy rövidített karakterosztályt sigilen kívül használsz, escape-elni kell: "\\d"

Alternációk

Az alternációknál a | speciális karakter jelzi, hogy az egyik vagy a másik lehetőségre illeszkedünk

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

Kvantifikátorok

A kvantifikátorok ismétlődő mintát tesznek lehetővé a reguláris kifejezésben. A kvantifikátort megelőző csoportra hatnak.

  • {N, M}, ahol N az ismétlődések minimális, M pedig a maximális száma
  • {N,} legalább N ismétlődésre illeszkedik
    • {0,} felírható *-ként is: nulla vagy több ismétlődésre illeszkedik
    • {1,} felírható +-ként is: egy vagy több ismétlődésre illeszkedik
  • {,N} legfeljebb N ismétlődésre illeszkedik

Csoportok

A kerek zárójelek (()) a csoportok és az elfogások jelölésére szolgálnak. A csoportot az esetek egy részében el is foghatjuk, hogy használatra visszakapjuk. Az Elixirben ezek lehetnek nevesítettek vagy névtelenek. Az elfogásokat úgy nevezzük el, hogy a nyitó zárójel után ?<name>-et írunk. A csoportok egyetlen egységként működnek, például amikor kvantifikátorok követik őket.

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

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

Horgonyok

A horgonyok ahhoz kellenek, hogy a reguláris kifejezést az illesztendő string elejéhez vagy végéhez kössük:

  • ^ a string elejéhez horgonyoz
  • $ a string végéhez horgonyoz

Interpoláció

Mivel a ~r a "pattern" |> Regex.escape() |> Regex.compile!() rövidítése, string-interpolációval dinamikusan is felépíthetsz egy reguláris kifejezés mintát:

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

Utasítások

Az a feladatod, hogy írj egy szolgáltatást, amely eseményeket dolgoz fel. Minden eseményhez tartozik egy dátum, de észreveszed, hogy három különböző formátumban küldik be őket a szolgáltatásod végpontjára:

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

Látod, hogy van némi hasonlóság köztük, ezért úgy döntesz, hogy írsz néhány összeépíthető reguláris kifejezésmintát.

1. Párosítsd a napot, a hónapot és az évet egy dátumból

Valósítsd meg a day/0, month/0 és year/0 függvényt úgy, hogy egy olyan string-mintát adjanak vissza, amely lefordítva a "01/01/1970" (dd/mm/yyyy) numerikus részeire illeszkedik. A nap és a hónap 1 vagy 01 formában is szerepelhet (nullákkal balra kiegészítve).

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

2. Párosítsd a hét napját és az év hónapját

Valósítsd meg a day_names/0 és month_names/0 függvényt úgy, hogy egy-egy olyan string-mintát adjanak vissza, amely lefordítva rendre a hét megnevezett napjára, illetve az év megnevezett hónapjára illeszkedik.

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

3. Rögzítsd a napot, a hónapot és az évet

Valósítsd meg a capture_day/0, capture_month/0, capture_year/0, capture_day_name/0 és capture_month_name/0 függvényt úgy, hogy egy olyan string-mintát adjanak vissza, amely a megfelelő részeket a következő nevek alá rögzíti: "day", "month", "year", "day_name", "month_name"

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

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

4. A rögzítések összekapcsolásával rögzítsd a teljes dátumot

Valósítsd meg a capture_numeric_date/0, capture_month_name_date() és capture_day_month_name_date/0 függvényt úgy, hogy egy olyan string-mintát adjanak vissza, amely a 3. részben szereplő részeket a megfelelő dátumformátum szerint rögzíti:

  • numerikus dátum - "01/01/1970"
  • hónapneves dátum - "January 1, 1970"
  • nap- és hónapneves dátum - "Thursday, January 1, 1970"
DateParser.capture_numeric_date()
|> Regex.compile!()
|> Regex.named_captures("01/01/1970")

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

5. Szűkítsd a rögzítést, hogy csak a dátumra illeszkedjen

Valósítsd meg a match_numeric_date/0, match_month_name_date/0 és match_day_month_name_date/0 függvényt úgy, hogy egy olyan lefordított reguláris kifejezést adjanak vissza, amely csak a dátumra illeszkedik, és a részeket is rögzíteni tudja.

"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"
#   }
Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg
Elixir Exercism

Készen állsz elkezdeni a(z) Dátumelemző feladatot?

Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Elixir nyelvet 58 fogalom168 feladat segítségével, valódi emberi mentorálással, mindez ingyen.