Tracks
/
Elixir
Elixir
/
Ejercicios
/
Analizador de fechas
Analizador de fechas

Analizador de fechas

Ejercicio de aprendizaje

Introducción

Expresiones regulares

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:

  • puedes usar muchos delimitadores distintos según lo que necesites, en lugar de /
  • los patrones de string ya están escapados; cuando escribes el patrón como string sin usar una regex, tendrás que escapar las barras invertidas (\)

Clases de caracteres

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"

Alternancias

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

Cuantificadores

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 repeticiones

Grupos

Los 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"]]

Anclas

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 string

Interpolación

Como ~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

Instrucciones

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.

1. Haz coincidir el día, el mes y el año de una fecha

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

2. Haz coincidir el día de la semana y el mes del año

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

3. Captura el día, el mes y el año

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"}

4. Combina las capturas para capturar la fecha completa

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:

  • fecha numérica - "01/01/1970"
  • fecha con nombre de mes - "January 1, 1970"
  • fecha con nombre de día y de mes - "Thursday, January 1, 1970"
DateParser.capture_numeric_date()
|> Regex.compile!()
|> Regex.named_captures("01/01/1970")

# => %{"day" => "01", "month" => "01", "year" => "1970"}

5. Restringe la captura para que coincida solo con la fecha

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"
#   }
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Elixir Exercism

¿Todo listo para empezar Analizador de fechas?

Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.