Tutorial de PERL en castellano : Dando vueltas sobre lo mismo

Preguntas frecuentemente preguntadas
Bibliografía.
Recursos Internet
Más difícil todavía
Ahorrando energías

Bucles, lectura de teclado y ficheros

Cuando, tras las elecciones, nuestro político corrupto sale reelegido por méritos propios, viene inmediatamente la recuperación económica y con ello el boom inmobiliario (favorecido por la recalificación en terrenos construibles de los parques de la ciudad). Tantas comisiones tiene que calcular, que decide escribir un programa que lo haga continuamente, en vez de tener que ejecutar el programa anterior cada vez. Decide además guardar detalles de todo en un fichero, que llevará en un disquete escondido en el collar del perro, para que, en caso de que lo investigue una comisión del Congreso, pueda tirar de la manta tecnológicamente. Saldría entonces algo como lo incluido en el listado siguiente:

#!/usr/bin/perl
open( MANTA, ">clientes");
while(1){
  print "Cliente\n";
  chop( $paganini = <STDIN> );
  last if !$paganini;
  print "Valor inmueble\n";
  chop( $valor= <STDIN> );
  $comision = $valor * 0.25;
  print "Comision = $comision\n";
  print MANTA "$paganini $comision\n";
}
close MANTA;
Listado : Programa manta.pl

En este segundo programa, que llamaremos manta.pl, se introducen algunos conceptos nuevos más. Para empezar, se utiliza la orden open para abrir un fichero; a esta orden se le dan dos parámetros, el filehandle por el cual nos vamos a referir al fichero en lo sucesivo, y una cadena que incluye el nombre del fichero y la forma de manejar ese fichero. En este caso, se usa la expresión ">clientes", que indica que se va a abrir para escritura. Otras opciones son las que aparecen en la tabla 1. Si no se pone nada, se supone que el fichero se abre para lectura. Y esto es fuente de continuas confusiones.

Como siempre, hay Más de Una Forma de Hacerlo TM, aunque no necesarimente más corta. Se puede meter el nombre del fichero en una variable tal como $MANTA, y abrirlo de la forma siguiente:


$MANTA='>prueba';
open MANTA;

Es decir, cuando no se pone una cadena detrás del filehandle, se usa el contenido de una variable que tenga el mismo nombre. Véase también que en este caso no he usado paréntesis detrás de open; son opcionales. Hay muchas más cosas sobre open leyendo el tutorial incluido en la documentación, se accede a él escribiendo perldoc perlopentut o man perlopentut.

> Abrir para escritura
>> Abrir para concatenar
< Abrir para lectura
>+ Abrir para lectura/escritura
¦ orden Ejecutar un programa que filtrará lo que se imprima en el fichero.
orden | Ejecutar una orden, de la cual se leerá la salida.
Tabla : Modos de apertura de ficheros

A continuación se comienza un bucle con la ordenwhile, que se ejecutará mientras la expresión entre paréntesis sea cierta, o sea, en este caso, en principio, siempre. Los valores "verdaderos" se indican en Perl con un número distinto de 0 o una cadena no nula. Tras while va siempre un bloque, que se comienza y termina con llaves. Dado que es un bloque, y no la alternativa orden|bloque (como sucede, por ejemplo, en el lenguaje C), se tendrán que utilizar siempre las llaves, aunque se trate de un solo comando. También se podría sustituir esta línea por until(0) {que tendría exactamente el mismo significado (recuerda, Hay Más De Una Forma de Hacerlo). O por dos o tres formas más, al menos.

En la línea 4 se hacen dos cosas juntas: se asigna a una variable lo que introduce el usuario, y a esta variable se le elimina el último carácter (chop, que significa trocear, como en el chopped). Esto es necesario porque, a diferencia de otros lenguajes, Perl incluye el retorno de carro en la cadena que lee. Lo eliminamos entonces para que quede todo bonito.

ETIQUETA while (EXPR) BLOQUE
ETIQUETA while (EXPR) BLOQUE continue BLOQUE 
ETIQUETA for (EXPR;EXPR;EXPR) BLOQUE 
ETIQUETA foreach VAR (MATRIZ) BLOQUE
Tabla : Tipos de bucles en Perl

En la línea 5 se utiliza una construcción típica:

Perl <comando> <condicional> <condición>.

En este caso, se sale del bucle (last) en caso de que lo que se haya leido sea la cadena vacía (recordad que previamente hemos eliminado el retorno de carro). Esta línea se podía haber sustituido por la siguientelast unless $paganini;que tiene exactamente el mismo significado (unless significa a menos que); en general, una sentencia en la que se utiliza if con una expresión verdadera se puede sustituir por otra en la que se utiliza unless con la misma expresión negada. Otras expresiones que regulan bucles son next, que ejecuta la iteración siguiente sin pasar por el resto de las órdenes del bucle, y redo, que vuelve a comenzar el bucle sin evaluar la condición.

lt, gt, le, geLexicográficamente menor, mayor, menor e igual, mayor e igual
eq, neIgual, distinto
cmpComparación de cadenas; devuelve -1, 0 o 1
xMultiplicación de cadenas "az" x 2 eq "azaz"
Tabla : operadores de cadenas en Perl

En esta misma línea se usa el operador !, de negación. Este operador, como otros muchos, están sacados directamente del lenguaje C, en general, los operadores en Perl son los mismos que en C, y además tienen la misma prioridad. Además, hay una serie de operadores específicos para cadenas alfanuméricas, sacados más bien del FORTRAN, y otros para ficheros que se verán  más adelante.

En la línea 10 se escribe en el fichero MANTA; como se ve, simplemente se incluye el filehandle delante de la expresión que se va a escribir. Para terminar, después de concluir el bucle se cierra el fichero.

Estos primeros programas nos permiten ya tener una idea de cómo funciona Perl. En realidad, salvo algunos asuntos menores de sintaxis de variables y su declaración, es muy similar al C: por eso siempre, la primera aproximación a un programa será hacerlo tal como uno lo haría en C, para luego, cuando se tenga mayor dominio del lenguaje Perl, hacerlo de forma más perlera.

El político corrupto se da cuenta de que tiene en un fichero guardadas una serie de sobornos anteriores en un fichero; pero no le puso nombre; así que, antes de que se le vayan las cosas de la memoria y no diga nada salvo en presencia de su abogado, decide hacer un programa que le vaya preguntando cantidad por cantidad quién fue la que se la dió. Y decide hacer el siguiente programa (recuerda.pl):


1 #!/usr/bin/perl
2 
3 open FICHERO, "cantidades";
4 open SALIDA, ">salida";
5 while($linea = <FICHERO>) {
6   chop($linea);
7   print "Quien te ha dado $linea pelas? Eh?\n";
8   chop( $menda = <STDIN> );
9   print SALIDA "$menda $linea\n";
10 }
11 close FICHERO;
12 close SALIDA;
Listado : Programa recuerda.pl

Este programa utiliza las mismas estructuras que el anterior: ficheros de entrada y salida, y un bucle. Sin embargo, se usan de forma diferente. Para empezar, la sintaxis de apertura de los ficheros en las líneas 3 y 4 es diferente: se evitan los paréntesis, casi 4 bytes, que en una memoria de 512 megabytes, quieras que no, es un ahorro. El fichero cantidades se abre para lectura, por lo que no es necesario poner el símbolo <, y el fichero salida se abre para escritura.

Lo que sigue es bastante típico de la lectura de ficheros en Perl: se lee una línea del fichero abierto (usando la construcción <>, se asigna a la variable $line. Además, la línea está dentro de una condición de continuación de un bucle; efectivamente, $line será la cadena vacía, y por lo tanto falso, cuando el fichero deje de tener elementos.

El interior del bucle no aporta nada nuevo: simplemente se le eliminan los retornos de carro a lo que se lee usando chop, y se combina la entrada con lo que introduce el usuario para escribirlo en la salida. Finalmente, en las líneas 11 y 12, se cierran los ficheros.

  1. Realizar un programa que vaya calculando cuadrados de números hasta que se introduzca una línea en blanco (solo retorno de carro).
  2. Realizar un programa que permita al usuario introducir un nombre, y el ordenador le escriba "Hola >mismo nombre en mayúsculas<".
  3. Realizar un programa que solicite nombres y apellidos del usuario, y los imprima en pantalla en formato formal: apellidos y nombre, separados por coma. Escribir en un fichero todos aquellos que se llamen Juan de nombre.
Ejercicios
[ Preguntas frecuentemente preguntadas] [ Bibliografía.] [ Recursos Internet] [ Más difícil todavía] [ Ahorrando energías]