Aprender
expresiones regulares no es fácil, pero por fortuna, con lo básico, se pueden hacer cosas muy potentes.
Perl, además, es el lenguaje que mejor uso hace de ellas, y que posee más potencia en sus patrones de búsqueda y sustitución. Es una de las partes fundamentales del lenguaje Perl, junto con CPAN y su comunidad.
En la documentación Perl encontrarás un montón de documentación sobre expresiones regulares. Tanto, que abruma.
Este es un listado de esos documentos, que muy posiblemente ya les tengas instalados en tu ordenador y que podrás consultarlos con el comando
perldoc. Si quieres leerlos en español, puedes pulsar en los siguientes enlaces.
- perlre - Manual sobre expresiones regulares en Perl
- perlrebackslash - Secuencias de escape en expresiones regulares en Perl
- perlrecharclass - Clases de caracteres en expresiones regulares Perl
- perlrequick - Guía rápida de las expresiones regulares
- perlreref - Referencia de expresiones regulares en Perl. Algo así como una tarjeta de referencia rápida
- perlretut - Tutorial de expresiones regulares
- perlfaq6 - Preguntas más frecuentes sobre expresiones regulares
Empieza con
perlrequick, y luego pasas a
perlfaq6 y
perlretut, para terminar en
perlre.
En estos foros encontrarás muchos cientos de ejemplos de problemas resueltos de forma rápida con la ayuda de las expresiones regulares.
En cuanto a la duda que tienes creo que te refieres a entender qué hace la línea 3 del código.
my @fecha = $dato =~ m{(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) ([ap])[.]m[.]}i;Esa línea es una asignación (=) a un array (@fecha), así que esperamos que la parte derecha de la asignación nos devuelva una lista de valores.
La parte derecha es una expresión regular:
$dato =~ m{(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) ([ap])[.]m[.]}i;Se usa el operador "=~" para aplicar la operación que hay a la derecha, a la cadena de caracteres que está almacenada en
$dato. La operación es de búsqueda ("m", de
match). Eso quiere decir que queremos buscar dentro de $dato algo que coincida con el patrón que está entre los delimitadores (las llaves {}). Además, la búsqueda queremos hacerla independientemente de si está en mayúsculas o minúsculas (la "i" del final).
El patrón es este:
(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) ([ap])[.]m[.] Lo que buscamos debe coincidir con él.
Aquí hay que decir que los patrones forman su propio lenguaje: algunos caracteres son literales pero otros tienen un significado especial. Por ejemplo, los paréntesis tienen la misión de "capturar" (guardarnos) aquello que coincida con el patrón que está dentro de ellos. Así, "(\d+)" quiere decir que queremos quedarnos con uno o más (+) dígitos (\d).
Entonces, con la primera parte del patrón,
(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+), estamos buscando: un número, seguido del carácter "/", seguido de otro número, seguido del carácter "/", seguido de otro número, seguido de un espacio en blanco, y sigue lo mismo con números separados con caracteres ":". O sea, que dentro de $dato estamos buscando fechas así:
01/01/2021 12:01:12. Y todos los números nos los vamos "guardando", por acción de los paréntesis.
Con la segunda parte del patrón,
([ap])[.]m[.], queremos buscar o coincidir con:
- ([ap]) - una letra, bien sea la "a" o la "p" (los corchetes forman una "clase de caracteres"); esa letra es guardada
- [.]m[.] - lo que sigue debe coincidir con: un punto, la letra "m", y otro punto; los puntos deben ir entre corchetes o escapados con "\" porque tienen un significado para las exp. reg., y no queremos eso, sino que buscamos un punto (literal)
Esta parte, entonces, está buscando por "a.m." o "p.m." (recordar que no nos importa si está en mayúsculas). Y la letra principal ("A" o "P") nos la guardamos.
Si... dentro de $dato, hay una combinación de caracteres que coincide con todo el patrón, el resultado será lo que hayamos almacenado en los paréntesis. Así que... @fecha almacenará
- los números de la fecha
- los números de la hora
- la letra "a" o "p"
(Si $dato no coincidiese, @fecha no contendrá ningún valor).
En la línea 5, le sumamos 12 a la cantidad de horas ($fecha[3]) si la letra que encontramos era una "p" (o "P", de ahí el lc()).
Queda, finalmente, la línea 6, donde vamos sacando de @fecha todos los valores en el orden que queremos, y se lo pasamos a printf() para que lo formatee y lo muestre bonito.