Las expresiones regulares (regex) son una herramienta poderosa para trabajar con strings en Elixir. Las expresiones regulares en Elixir siguen la especificación PCRE (Perl Compatible Regular Expressions). Los patrones de string que representan el significado de la expresión regular se compilan primero y luego se usan para coincidir con todo o parte de un string.
En Elixir, la forma más común de crear expresiones regulares es usando el sigilo ~r. Los sigilos proporcionan atajos de azúcar sintáctico para tareas comunes en Elixir. Para coincidir con un string literal, podemos usar el propio string como patrón después del sigilo.
~r/test/
El operador =~/2 es útil para realizar una coincidencia de regex en un string y devolver un resultado boolean.
"this is a test" =~ ~r/test/
# => true
Dos notas sobre el uso de sigilos:
/
\)Coincidir con un rango de caracteres usando corchetes [] define una clase de caracteres. Esta coincidirá con cualquier carácter individual de los caracteres de la clase. También puedes especificar un rango de caracteres como a-z, siempre que el inicio y el final representen un rango contiguo de puntos de código.
regex = ~r/[a-z][ADKZ][0-9][!?]/
"jZ5!" =~ regex
# => true
"jB5?" =~ regex
# => false
Las clases de caracteres abreviadas hacen que el patrón sea más conciso. Por ejemplo:
\d es la abreviatura de [0-9] (cualquier dígito)\w es la abreviatura de [A-Za-z0-9_] (cualquier carácter de palabra)\s es la abreviatura de [ \t\r\n\f] (cualquier carácter de espacio en blanco)Cuando se usa una clase de caracteres abreviada fuera de un sigilo, debe escaparse: "\\d"
Las alternancias usan | como carácter especial para indicar la coincidencia con uno u otro
regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true
Los cuantificadores permiten un patrón repetitivo en la regex. Afectan al grupo que precede al cuantificador.
{N, M} donde N es el número mínimo de repeticiones y M es el máximo{N,} coincide con N o más repeticiones
{0,} también puede escribirse como *: coincide con cero o más repeticiones{1,} también puede escribirse como +: coincide con una o más repeticiones{,N} coincide con hasta N repeticionesLos paréntesis () se usan para denotar grupos y capturas. El grupo también puede ser capturado en algunos casos para ser devuelto y usado. En Elixir, estos pueden tener nombre o no. Las capturas se nombran añadiendo ?<name> después del paréntesis de apertura. Los grupos funcionan como una sola unidad, como cuando van seguidos de cuantificadores.
regex = ~r/(h)at/
Regex.replace(regex, "hat", "\\1op")
# => "hop"
regex = ~r/(?<letter_b>b)/
Regex.scan(regex, "blueberry", capture: :all_names)
# => [["b"], ["b"]]
Las anclas se usan para vincular la expresión regular al principio o al final del string que se va a comparar:
^ ancla al principio del string$ ancla al final del stringDado que ~r es un atajo para "pattern" |> Regex.escape() |> Regex.compile!(), también puedes usar la interpolación de strings para construir dinámicamente un patrón de expresión regular:
anchor = "$"
regex = ~r/end of the line#{anchor}/
"end of the line?" =~ regex
# => false
"end of the line" =~ regex
# => true
Te han encargado escribir un servicio que ingiere eventos. Cada evento tiene una fecha asociada, pero te das cuenta de que se están enviando 3 formatos diferentes al endpoint de tu servicio:
"01/01/1970""January 1, 1970""Thursday, January 1, 1970"Puedes ver que hay algunas similitudes entre cada uno de ellos y decides escribir algunos patrones de expresiones regulares componibles.
Implementa day/0, month/0 y year/0 para que devuelvan un patrón de string que, al compilarse, coincida con los componentes numéricos de "01/01/1970" (dd/mm/yyyy). El día y el mes pueden aparecer como 1 o 01 (con ceros a la izquierda).
"31" =~ DateParser.day() |> Regex.compile!()
# => true
"12" =~ DateParser.month() |> Regex.compile!()
# => true
"1970" =~ DateParser.year() |> Regex.compile!()
# => true
Implementa day_names/0 y month_names/0 para que devuelvan un patrón de string que, al compilarse, coincida con el nombre del día de la semana y con el nombre del mes del año, respectivamente.
"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 y capture_month_name/0 para que devuelvan un patrón de string que capture los componentes respectivos en los nombres: "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() y capture_day_month_name_date/0 para que devuelvan un patrón de string que capture los componentes de la parte 3 usando el formato de fecha correspondiente:
"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 y match_day_month_name_date/0 para que devuelvan una expresión regular compilada que solo coincida con la fecha y que además pueda capturar los 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"
# }
Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.