Tutorial de PERL en castellano : Recordando, que es gerundio

Preguntas frecuentemente preguntadas
Bibliografía.
Recursos Internet
Purgando los pecados.

La orden split, matrices asociativas y matrices bidimensionales

Al final del día, nuestro político corrupto reflexiona. ¿De qué sirve tanto trabajo, sin una buena contabilidad consolidada? (Además, tiene que presentarle las cuentas al señor X a fin de mes). Idea, pues, el programa que aparece en el listado 4.

die "Y el fichero de clientes, ein?\n" unless $ARGV[0];
2 while(<>) {
3   @linea = split;
4   @fecha=split(/\//,$linea[$#linea]);
$mesdia = "$fecha[1]-$fecha[0]";
6   $pasta=$linea[$#linea - 2];
$totalDia{$mesdia}+=$pasta;
8 }
9 
10 foreach (sort keys %totalDia) {
11   print "Trinque total del dia $_ = $totalDia{$_}\n";
12 }
Listado : Programa totales.pl

Este programa, aplicado sobre el fichero clientes.mas, (resultado de una incursión en la construcción de diversas viviendas para los cuerpos de seguridad del estado y sus departamentos de investigación y desarrollo, así como otros procedentes del mundo de la enseñanza) da el siguiente resultado (o algo parecido)

C:\PROGS\PERL>perl totales.pl clientes.mas
Trinque total del dia 3-24 = 598454.75
Trinque total del dia 4-25 = 1100987
Trinque total del dia 4-26 = 487775

Este programa empieza con una advertencia: "muere si no me metes un fichero como argumento". La orden die termina el programa con un mensaje; mientras que el condicional que lo sigue comprueba que exista al menos un argumento para el programa; la matriz @ARGV contiene los argumentos pasados al programa; de forma que $#ARGV dará el índice del último argumento, o sea que si es -1, indicará que no se ha pasado ningún argumento. Y otra forma de hacerlo sería

die "Sin argumento me lamento\n" if $#ARGV < 0;

O incluso

$ARGV[0] || die "Te has quedado sin argumentos\n";

que mira lo que hay a la izquierda del || (que es el "o" lógico), y si es cierto, ejecuta lo que hay a la derecha. Recuerda, en PERL hay más bla, bla.

El siguiente bucle, que comienza en la línea 2, tiene una extraña condición para que el bucle siga; sólo los dos ángulos enfrentados. Teóricamente, debería de haber un filehandle dentro de esos ángulos (como se ha visto en un ejemplo anterior), pero en este caso, se está tomando el fichero por defecto, que es el fichero que se introduce como argumento; en caso de que no se hubiera introducido ninguno tomaría entrada estándar, es decir, que habría que introducirle cada línea mediante teclado. A la vez, y como se ha visto, esa orden toma una línea del fichero y la deposita en la variable por defecto, aunque, ojo, no le quita el retorno de carro final. Hay que tener en cuenta que los paréntesis angulares sin argumento extraen elementos del array @ARGV usando pop, y abren un fichero con ese nombre; o sea que si hubiera varios nombres de fichero en la línea de comandos, los iría abriendo uno por uno y disminuyendo consecuentemente el tamaño de @ARGV; conclusión, que si necesitas @ARGV para algo, mejor que lo guardes antes de meterte en un bucle de esta guisa.

Sobre la variable por defecto actúa la orden split (una de las cosas más usadas en PERL), dividiéndola en una serie de cadenas separadas por espacios y depositando cada una de esas cadenas en un elemento de la matriz @linea. Y dese cuenta el venerado público de con qué facilidad hemos hecho algo que requeriría al menos 10 líneas de cualquier otro lenguaje. No hay que dimensionar matrices, no hay que recorrer la cadena caracter por caracter... ¡Nada!(3). Perdón, me he dejado llevar por el entusiasmo.

La fecha es, en todos los casos, la última cadena de la línea; es decir, que será el último elemento de la matriz (cuyo subíndice es siempre $#<nombre-matriz)), pero a su vez tendremos que dividirlo, esta vez por la barra de separación, para luego poder poner el mes delante y que salga todo bellamente ordenado por meses en vez de por días.

Esta cadena con la fecha, más la pasta, que está siempre 2 posiciones más a la izquierda (independientemente de la longitud de los nombres), se utiliza en la línea 7 en una matriz asociativa. Esta es otra de las características más potentes del PERL, se pueden usar matrices cuyo índice es una cadena cualquiera, no sólo números enteros positivos. Estas matrices asociativas encierran sus índices o claves entre llaves (¿os dáis cuenta del sutil mnemónico?). En esa línea, se le añade al componente de la matriz indexado por la fecha la pasta de la entrada correspondiente. Así, hasta que se termina el fichero de entrada.

Para imprimir el informe, tres cuartos de lo mismo que en el programa anterior, salvo que en este caso, una matriz asociativa completa se indica con %, en vez de la arroba.

  1. Leer un fichero con el formato Primer_Apellido Segundo_Apellido, Nombre y escribirlo como
    Nombre Primer_Apellido Segundo_Apellido
  2. En el mismo fichero, presentar al final el número de veces que aparece cada apellido.
  3. Realizar un programa que, haciendo lo mismo que el manta.pl, lo haga en la mitad de líneas.
  4. Escribir un programa que haga lo mismo que la orden wc de UNIX, es decir, para cualquier fichero, contar el número de líneas, de palabras y de bytes, y presentarlo en 3 columnas con el nombre del fichero en la cuarta. Hacer que funcione para varios ficheros, introducidos en la línea de comandos.
  5. A partir del fichero de registro de visitas de un sitio Web, o log, poner cuántasveces han consultado las páginas desde dominios de primer y segundo orden, presentarlos por orden, con una opción que permita seleccionar primer o segundo orden.
  6. Realizar un programa que, a partir de una lista del tipo DNI Apellidos, Nombre genere un fichero de password, con el formato
    username:password:uid:gid:Nombre y Apellidos
    Calcular el username con la inicial del nombre y el primer apellido; si existe, usar el segundo apellido, y si existe también, añadir un número de orden. Para el password, encriptar el DNI; el UID se genera por orden alfabético a partir del número 1000, el gid es un entero común, y el nombre y apellidos es elindicado. Al terminarlo, ofrecerlo amablemente al administrador del sistema de tu Escuela o Facultad.
Ejercicios

[v5]A partir de la versión 5 de perl, se pueden usar matrices bidimensionales, mediante un mecanismo que se llama referencias; este mecanismo no nos interesa ahora mismo, pero sí como podemos usarlo en nuestros programas, tales como el siguiente (totales-v5.pl):


1  #!/usr/bin/perl
2  $ARGV[0] || die "¡Dime el nombre del fichero de clientes, cohone!\n";
3  while(<>) {
4    @linea = split;
5    @fecha=split(/\//,$linea[$#linea]);
6    $pasta=$linea[$#linea - 2];
7    $totalDia[$fecha[1]][$fecha[0]]+=$pasta;
8  }
9  
10 for ( $i = 1; $i <= $#totalDia; $i++ ) {
11   @dias = @{$totalDia[$i]};
12   for ( $j = 1; $j <= $#dias; $j ++ ) {
13     print "Trinque total del dia $j del $i = $totalDia[$i][$j]\n" if $totalDia[$i][$j];
14   }
15 }
Listado : Programa totales-v5.pl

Este programa es bastante parecido al anterior, salvo que, en vez de almacenarse los resultados en un array asociativo, se almacenan en un array bidimensional; la primera dimensión es el mes, y la segunda representa el día del mes. La línea 2 cambia simplemente para indicar otra forma de detectar si hay un fichero en la línea de comandos o imprimir un mensaje de error.

La línea 7 es la que usa una matriz bidimensional. Hasta aquí, todo normal; lo único relevante es que no hay que dimensionarla. Como primer índice de la matriz se usa el elemento 1 de $linea, es decir, el mes, y como segundo índice el primer elemento (el 0), es decir, el día.

Donde sí se nota un cambio es a partir de la línea 10; el bucle lo hacemos sobre una matriz normal y corriente. El problema es que, tal como sucede en las matrices bidimensionales en C, en PERL las matrices bidimensionales son en realidad una matriz de matrices, o mejor una matriz de referencias. Por eso, en la línea 11 lo que se hace es dereferenciar el elemento correspondiente y convertirlo en una matriz que podamos usar, la matriz @dias. En la línea 13, usando interpolación, se imprimen todos los elementos que son no nulos (if $totalDia[$i][$j]) la mayoría serán nulos , y los dejamos sin imprimir. [/v5]

  1. Realizar un programa que lea un fichero organizado en filas y columnas, tal como este
    uno dos tres
    cuatro cinco seis
    siete ocho nueve
    
    y genere un documento HTML con los contenidos del fichero organizados en una tabla; cada elemento del fichero deberá ir en una celda diferente, así
    uno dos tres
    cuatro cinco seis
    siete ocho nueve
    Aunque no es estrictamente necesario, usad una matriz bidimensional para hacerlo.
Ejercicios
[ Preguntas frecuentemente preguntadas] [ Bibliografía.] [ Recursos Internet] [ Purgando los pecados.]