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 después se usan para hacer coincidir todo o parte de un string.
En Elixir, la forma más común de crear expresiones regulares es usar el sigilo ~r. Los sigilos ofrecen atajos de azúcar sintáctico para tareas comunes en Elixir. Para hacer coincidir un literal de string, podemos usar el propio string como patrón después del sigilo.
~r/test/
El operador =~/2 es útil para hacer 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 los sigilos:
/
\)Hacer coincidir un rango de caracteres usando corchetes [] define una clase de caracteres. Esto hace que cualquier carácter individual coincida con 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 forma corta de [0-9] (cualquier dígito)\w es la forma corta de [A-Za-z0-9_] (cualquier carácter de «palabra»)\s es la forma corta de [ \t\r\n\f] (cualquier carácter de espacio en blanco)Cuando usas una clase de caracteres abreviada fuera de un sigilo, debes escaparla: "\\d"
Las alternancias usan | como carácter especial para indicar que coincide con uno o con otro
regex = ~r/cat|bat/
"bat" =~ regex
# => true
"cat" =~ regex
# => true
Los cuantificadores permiten un patrón repetido 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 se puede escribir como *: coincide con cero o más repeticiones{1,} también se puede escribir como +: coincide con una o más repeticiones{,N} coincide con hasta N repeticionesLos paréntesis () se usan para indicar grupos y capturas. En algunos casos, el grupo también puede capturarse para devolverlo y usarlo. En Elixir, estas pueden tener nombre o no. Las capturas se nombran agregando ?<name> después del paréntesis de apertura. Los grupos funcionan como una sola unidad, por ejemplo cuando los sigue un cuantificador.
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 fijar la expresión regular al inicio o al final del string que quieres hacer coincidir:
^ se ancla al inicio del string$ se ancla al final del stringComo ~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 recibe eventos. Cada evento tiene una fecha asociada, pero notas 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, así que decides escribir algunos patrones de expresiones regulares componibles.
Implementa day/0, month/0 y year/0 para que devuelvan un patrón de cadena 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 (rellenados por la izquierda con ceros).
"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 cadena que, al compilarse, coincida con el nombre del día de la semana y 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, capture_month_name/0 para que devuelvan un patrón de cadena que capture los componentes respectivos con 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 cadena 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.