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 depois usados para fazer a correspondência de toda a string ou de parte dela.
Em Elixir, a forma mais comum de criar expressões regulares é usando o sigilo ~r. Os sigilos oferecem 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 logo após o sigilo.
~r/test/
O operador =~/2 é útil para fazer uma correspondência de regex em uma string e retornar um resultado boolean.
"this is a test" =~ ~r/test/
# => true
Duas observações sobre o uso de sigilos:
/
\)Corresponder a um intervalo de caracteres usando colchetes [] define uma classe de caracteres. Isso corresponde a qualquer um dos caracteres da classe. Você também pode especificar um intervalo de caracteres 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
Classes de caracteres abreviadas deixam o padrão mais conciso. Por exemplo:
\d, abreviação de [0-9] (qualquer dígito)\w, abreviação de [A-Za-z0-9_] (qualquer caractere de 'palavra')\s, abreviação de [ \t\r\n\f] (qualquer caractere de espaço em branco)Quando uma classe de caracteres abreviada é usada fora de um sigilo, ela precisa ser escapada: "\\d"
As alternâncias usam | como caractere especial para indicar a correspondência de um ou outro
regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true
Os quantificadores permitem um padrão repetido na regex. Eles afetam o grupo que vem antes do quantificador.
{N, M}, em que N é o número mínimo de repetições e M é o máximo{N,} corresponde a N repetições ou mais
{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çõesParênteses () são usados para denotar grupos e capturas. Em alguns casos, o grupo também pode ser capturado para ser retornado e usado. Em Elixir, eles 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 unidade única, como quando são seguidos por 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 são usadas para prender a expressão regular ao início ou ao fim da string que será correspondida:
^ ancora no início da string$ ancora no fim da stringComo o ~r é um atalho para "pattern" |> Regex.escape() |> Regex.compile!(), você também pode usar interpolação de string para montar 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
Você tem a tarefa de escrever um serviço que recebe eventos. Cada evento tem uma data associada, mas você percebe que 3 formatos diferentes estão sendo enviados ao endpoint do seu serviço:
"01/01/1970""January 1, 1970""Thursday, January 1, 1970"Você consegue ver que existem algumas semelhanças entre cada um deles e decide escrever alguns padrões de expressão regular componíveis.
Implemente day/0, month/0 e year/0 para retornar um padrão de string que, quando compilado, corresponda aos componentes numéricos em "01/01/1970" (dd/mm/yyyy). O dia e o mês podem aparecer como 1 ou 01 (preenchidos com zeros à esquerda).
"31" =~ DateParser.day() |> Regex.compile!()
# => true
"12" =~ DateParser.month() |> Regex.compile!()
# => true
"1970" =~ DateParser.year() |> Regex.compile!()
# => true
Implemente day_names/0 e month_names/0 para retornar um padrão de string que, quando compilado, corresponda ao nome do dia da semana e ao nome do mês do ano, respectivamente.
"Tuesday" =~ DateParser.day_names() |> Regex.compile!()
# => true
"June" =~ DateParser.month_names() |> Regex.compile!()
# => true
Implemente capture_day/0, capture_month/0, capture_year/0, capture_day_name/0, capture_month_name/0 para retornar um padrão de string que captura os respectivos componentes com os nomes: "day", "month", "year", "day_name", "month_name"
DateParser.capture_month_name()
|> Regex.compile!()
|> Regex.named_captures("December")
# => %{"month_name" => "December"}
Implemente capture_numeric_date/0, capture_month_name_date(), e capture_day_month_name_date/0 para retornar um padrão de string que captura os componentes da parte 3 usando o respectivo 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"}
Implemente match_numeric_date/0, match_month_name_date/0, e match_day_month_name_date/0 para retornar uma expressão regular compilada que corresponda apenas à data, e que também possa 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"
# }
Crie sua conta no Exercism para aprender e dominar Elixir com 58 conceitos168 exercícios e mentoria humana de verdade, tudo de graça.