As expressões regulares (regex) são uma ferramenta poderosa para trabalhar com strings em Elixir. As expressões regulares em Elixir seguem a especificação PCRE (Perl Compatible Regular Expressions). Os padrões de string que representam o significado da expressão regular são primeiro compilados e só depois usados para corresponder a toda a string ou a parte dela.
Em Elixir, a forma mais comum de criar expressões regulares é usar o sigil ~r. Os sigils fornecem atalhos de açúcar sintático para tarefas comuns em Elixir. Para corresponder a um literal de string, podemos usar a própria string como padrão a seguir ao sigil.
~r/test/
O operador =~/2 é útil para efetuar uma correspondência de regex numa string e devolver um resultado boolean.
"this is a test" =~ ~r/test/
# => true
Duas notas sobre a utilização de sigils:
/, consoante aquilo de que precisas\)Corresponder a um intervalo de carateres com parênteses retos [] define uma classe de carateres. Isto corresponde a um único caráter pertencente à classe. Também podes especificar um intervalo de carateres como a-z, desde que o início e o fim representem um intervalo contíguo de pontos de código.
regex = ~r/[a-z][ADKZ][0-9][!?]/
"jZ5!" =~ regex
# => true
"jB5?" =~ regex
# => false
As classes de carateres abreviadas tornam o padrão mais conciso. Por exemplo:
\d é a forma abreviada de [0-9] (qualquer algarismo)\w é a forma abreviada de [A-Za-z0-9_] (qualquer caráter de "palavra")\s é a forma abreviada de [ \t\r\n\f] (qualquer caráter de espaço em branco)Quando usas uma classe de carateres abreviada fora de um sigil, tens de a escapar: "\\d"
As alternâncias usam | como caráter especial para indicar a correspondência com um ou outro
regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true
Os quantificadores permitem um padrão repetido na regex. Afetam o grupo que precede o quantificador.
{N, M} onde N é o número mínimo de repetições e M é o máximo{N,} corresponde a N ou mais repetições
{0,} também pode ser escrito como *: corresponde a zero ou mais repetições{1,} também pode ser escrito como +: corresponde a uma ou mais repetições{,N} corresponde a até N repetiçõesOs parênteses curvos () são usados para denotar grupos e capturas. Nalguns casos, o grupo também pode ser capturado para ser devolvido e usado. Em Elixir, estes podem ser nomeados ou não nomeados. As capturas são nomeadas acrescentando ?<name> depois do parêntese de abertura. Os grupos funcionam como uma única unidade, tal como quando são seguidos de quantificadores.
regex = ~r/(h)at/
Regex.replace(regex, "hat", "\\1op")
# => "hop"
regex = ~r/(?<letter_b>b)/
Regex.scan(regex, "blueberry", capture: :all_names)
# => [["b"], ["b"]]
As âncoras servem para fixar a expressão regular ao início ou ao fim da string com que queremos corresponder:
^ fixa ao início da string$ fixa ao fim da stringComo o ~r é um atalho para "pattern" |> Regex.escape() |> Regex.compile!(), também podes usar interpolação de strings para construir dinamicamente um padrão de expressão regular:
anchor = "$"
regex = ~r/end of the line#{anchor}/
"end of the line?" =~ regex
# => false
"end of the line" =~ regex
# => true
Tens a tarefa de escrever um serviço que ingere eventos. Cada evento tem uma data associada, mas reparas que estão a ser submetidos três formatos diferentes ao endpoint do teu serviço:
"01/01/1970""January 1, 1970""Thursday, January 1, 1970"Consegues ver que existem algumas semelhanças entre si e decides escrever alguns padrões de expressões regulares que se podem compor.
Implementa day/0, month/0 e year/0 para devolver um padrão de string que, quando compilado, corresponde aos componentes numéricos em "01/01/1970" (dd/mm/yyyy). O dia e o mês podem aparecer como 1 ou 01 (preenchidos à esquerda com zeros).
"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 para devolver um padrão de string que, quando compilado, corresponde ao nome do dia da semana e ao nome do mês do ano, respetivamente.
"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, capture_month_name/0 para devolver um padrão de string que captura os respetivos componentes com os nomes: "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 para devolver um padrão de string que captura os componentes da parte 3 utilizando o respetivo formato de 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 para devolver uma expressão regular compilada que apenas corresponde à data e que também consegue capturar os componentes.
"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"
# }
Inscreve-te no Exercism para aprenderes e dominares Elixir com 58 conceitos168 exercícios, e mentoria humana real, tudo grátis.