Le espressioni regolari (regex) sono uno strumento potente per lavorare con le stringhe in Elixir. Le espressioni regolari in Elixir seguono la specifica PCRE (Perl Compatible Regular Expressions). I pattern di stringa che rappresentano il significato dell'espressione regolare vengono prima compilati e poi usati per trovare corrispondenze in tutta o parte di una stringa.
In Elixir, il modo più comune per creare espressioni regolari è usare il sigillo ~r. I sigilli forniscono scorciatoie di zucchero sintattico per attività comuni in Elixir. Per trovare una stringa letterale, possiamo usare la stringa stessa come pattern dopo il sigillo.
~r/test/
L'operatore =~/2 è utile per eseguire una corrispondenza regex su una stringa e restituire un risultato boolean.
"this is a test" =~ ~r/test/
# => true
Due note sull'uso dei sigilli:
/
\)La corrispondenza di un intervallo di caratteri tramite parentesi quadre ([]) definisce una classe di caratteri. Questa corrisponde a un singolo carattere qualsiasi tra i caratteri della classe. Puoi anche specificare un intervallo di caratteri come a-z, purché l'inizio e la fine rappresentino un intervallo contiguo di punti di codice.
regex = ~r/[a-z][ADKZ][0-9][!?]/
"jZ5!" =~ regex
# => true
"jB5?" =~ regex
# => false
Le classi di caratteri abbreviate rendono il pattern più conciso. Per esempio:
\d è l'abbreviazione di [0-9] (qualsiasi cifra)\w è l'abbreviazione di [A-Za-z0-9_] (qualsiasi carattere «di parola»)\s è l'abbreviazione di [ \t\r\n\f] (qualsiasi carattere di spaziatura)Quando una classe di caratteri abbreviata viene usata fuori da un sigillo, deve essere sottoposta a escape: "\\d"
Le alternanze usano | come carattere speciale per indicare la corrispondenza con uno o l'altro
regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true
I quantificatori consentono un pattern ripetuto nella regex. Influenzano il gruppo che precede il quantificatore.
{N, M} dove N è il numero minimo di ripetizioni e M è il massimo{N,} corrisponde a N o più ripetizioni
{0,} può anche essere scritto come *: corrisponde a zero o più ripetizioni{1,} può anche essere scritto come +: corrisponde a una o più ripetizioni{,N} corrisponde fino a N ripetizioniLe parentesi tonde (()) sono usate per indicare gruppi e catture. Il gruppo può anche essere catturato in alcuni casi per essere restituito e usato. In Elixir, possono essere con nome o senza nome. Le catture vengono nominate aggiungendo ?<name> dopo la parentesi aperta. I gruppi funzionano come un'unica unità, come quando sono seguiti da quantificatori.
regex = ~r/(h)at/
Regex.replace(regex, "hat", "\\1op")
# => "hop"
regex = ~r/(?<letter_b>b)/
Regex.scan(regex, "blueberry", capture: :all_names)
# => [["b"], ["b"]]
Le ancore sono usate per ancorare l'espressione regolare all'inizio o alla fine della stringa da confrontare:
^ ancora all'inizio della stringa$ ancora alla fine della stringaPoiché ~r è una scorciatoia per "pattern" |> Regex.escape() |> Regex.compile!(), puoi anche usare l'interpolazione di stringhe per costruire dinamicamente un pattern di espressione regolare:
anchor = "$"
regex = ~r/end of the line#{anchor}/
"end of the line?" =~ regex
# => false
"end of the line" =~ regex
# => true
Il tuo compito è scrivere un servizio che riceve eventi. Ogni evento ha una data associata, ma ti accorgi che al tuo endpoint vengono inviati 3 formati diversi:
"01/01/1970""January 1, 1970""Thursday, January 1, 1970"Noti che ci sono alcune somiglianze tra loro e decidi di scrivere delle espressioni regolari componibili.
Implementa day/0, month/0 e year/0 in modo che restituiscano un pattern di stringa che, una volta compilato, corrisponda alle componenti numeriche in "01/01/1970" (dd/mm/yyyy). Il giorno e il mese possono comparire come 1 o 01 (riempiti a sinistra con degli zeri).
"31" =~ DateParser.day() |> Regex.compile!()
# => true
"12" =~ DateParser.month() |> Regex.compile!()
# => true
"1970" =~ DateParser.year() |> Regex.compile!()
# => true
Implementa day_names/0 e month_names/0 in modo che restituiscano un pattern di stringa che, una volta compilato, corrisponda rispettivamente al giorno della settimana e al mese dell'anno indicati per nome.
"Tuesday" =~ DateParser.day_names() |> Regex.compile!()
# => true
"June" =~ DateParser.month_names() |> Regex.compile!()
# => true
Implementa capture_day/0, capture_month/0, capture_year/0, capture_day_name/0 e capture_month_name/0 in modo che restituiscano un pattern di stringa che cattura le rispettive componenti assegnando loro i nomi: "day", "month", "year", "day_name", "month_name"
DateParser.capture_month_name()
|> Regex.compile!()
|> Regex.named_captures("December")
# => %{"month_name" => "December"}
Implementa capture_numeric_date/0, capture_month_name_date() e capture_day_month_name_date/0 in modo che restituiscano un pattern di stringa che cattura le componenti della parte 3 usando il rispettivo formato di data:
"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"}
Implementa match_numeric_date/0, match_month_name_date/0 e match_day_month_name_date/0 in modo che restituiscano un'espressione regolare compilata che corrisponde solo alla data e che riesce anche a catturare le componenti.
"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"
# }
Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.