La dificultad de enseñar Perl como un primer lenguaje de programación está en que
tus estudiantes no lo apreciaran hasta que comiencen con su segundo lenguaje. Lo
complicado de enseñar Perl como segundo lenguaje es que no hay un primer lenguaje
conveniente para partir de allí.
-- Larry Wall
Cuando dicen que Perl es un `lenguaje glue', lo que realmente dicen es que es bueno
para limpiar los errores después de otros programas
-- Mark-Jason Dominus en comp.lang.perl.misc
Panoráma
Este mes veremos los condicionales y los contructores de ciclos, y examinaremos unos
cuantos de los scripts que usan. También exploraremos como trabajar con variables
Perl, y echaremos un vistazo rápido a la capturación de la entrada usuario. Una vez que
entiendas esta parte, te sugiero practicar con un par de scripts
experimentales y jugar con ellos; seguro, que cometeras errores - pero de aquí en
adelante, necesitarás sustituir tus lecturas para bajar y ensuciarte. Si no juegas, no
puedes ganar.
Condicionales
Aquí están las declaraciones de condicionales que Perl usa; nada particularmente inusual, si estás acostumbrado a los condicionales en otros lenguajes. Perl revisa si la condición es verdadera o falsa, y bifurca la ejecución con base en eso.
if ( traffic_light_is_red ) { # Si la condición
1 es verdadera, has
stop;
# Acción 1
}
elsif ( traffic_light_is_yellow ) { # Si la condición 2 es verdadera, has
hit_the_gas;
# Acción 2
}
else {
# En todos los demás casos, has
proceed_with_caution; # Acción 3
}
Nota que la cláusula "elsif" no es requerida; y tampoco lo es el "else". También observa que "else" es la "opción atrapa-todo": si ligth es cualquier cosa excepto rojo o amarillo - apagado, solo consigue rebajar por accidente, etc. - la acción es 'proceed_with_caution'.
A diferencia de C, cada acción debe ser encerrada en un bloque ( definido por los corchetes):
if ( $tomato eq "red" ) print
"Ripe.\n"; # ¡INCORRECTO!
if ( $tomato eq "red" ) { print "Ripe.\n"; } #
Correcto
unless ( $blarg == $foo ) { # Si
la condición 1 es false, has
print
"Unequal!.\n"; # Acción 1
}
else
{
# De otra forma, has
print "They're
equal.\n"; # Acción 2
}
Bastante obvio. Esto ayudará a pensar en "unless" como el condicional
"si no". De nuevo, el "else" es opcional. No, no hay cosas como
"elseunless". :)
Ciclos
Ah, ciclos maravillosos. Estas son las cosas que hacen que las acciones sucedan, tantas veces como queramos, basados en una condición. Podrías decir que los ciclos son la principal razón de las computadoras en general, su principal uso como las herramientas que son es: repetir trabajo. Aquí están los tres tipos más comunes de ciclos en Perl:
while ( $cat eq "away" )
{ # Mientras la
condición 1 sea verdadera, has
print "The mice will play.\n"; #
Acción 1
}
until ( $time > 1159 ) { # Mientras la
condición 1 sea falsa, has
print "It's morning.\n" # Acción 1
}
El ciclo "for" puede ser implementado en dos formas diferentes -una es como el
ciclo "for" en C:
for ( $n = 99; $n > 0; $n-- ) {
print "$n bottles of beer on the wall, $n bottles of beer,";
...
}
En este caso, ponemos $n con un valor inicial (99), decrementamos en 1 cada vez que entramos en el ciclo, y checamos para estar seguros que $n sea menor que 0. Si no lo es, salimos del ciclo.
El segundo método, es algo como el ciclo Clipper, FoxPro, etc. "foreach", es por mucho el más común:
foreach $n ( 0..1000 ) {
print "Day $n on this deserted island. So
far, I've had ";
print $n * 100, " bananas. I hope I'm
rescued soon.\n";
...
}
Puede también ser usado de la siguiente manera:
for ( 0..1000 ) {
print "Day $_ on this deserted island. So far, I've had ";
print $_ * 100, " bananas. I hope I'm rescued soon.\n";
...
}
Nuestro viejo amigo, el "$_" (explicado en la parte previa de esta serie.). Efectivamente viene bien. Nota que "foreach" es solo un alias para "for", y que se pueden usar indistintamente.
Todos los condicionales y ciclos anteriores pueden también ser usados como modificadores de declaraciones solas, como sigue:
print "This is line $_ of 50.\n" for ( 1..50 );
Lo anterior imprimirá 50 líneas, numeradas en la forma obvia.
print "I've found him!" if /Waldo/;
La línea de arriba será impresa si el buffer default ($_) contiene un "Waldo".
Un hecho interezante que combina bien con ciclos y condicionales es que variables vacias en Perl regresan un valor null - que es "false". Esto es perfecto para verificarlas:
print if $_; # Imprime $_ si contiene algo
El siguiente ejemplo muestra que un valor cero tambien es falso:
print "5280 is true.\n" if 5280; # Esto imprimirá. print "0 is true.\n" if 0; # Esto no imprimirá.
Aquí hay un ejemplo con una lista:
while ( @a ) {
print pop @a; # "Pop" el
último valor de @a y lo imprime
$count = @a; # Obtiene el
número de elementos en @a
print $count, " elements left in \@a.\n";
}
Cuando el último elemento se ha ido, el ciclo termina.
unless ( %hash ) {
%hash = ( 'first' => 'Mighty Joe',
'last' => 'Young',
'type' => 'gorilla',
'from' => 'Pangani Mountains',
'born' => '1949',
'Mom' => 'Jill',
'Dad' => 'Gregg'
);
}
Si "%hash" es vacio, lo poblamos con algunos valores iniciales.
El operador rango, que hemos usado un par de veces hasta ahora, es usado ampliamente: este te permite especificar un rango de números o letras. Nota que los rangos tienen que ser del mismo 'tipo' - si especificas ( 'a'..'Z') o ('A'..'z'), la salida no será lo que esperas. Tampoco puedes especificar ( 'z'..'a'); porque tampoco trabajará. Sin embargo, hay una forma fácil de hacerlo:
foreach $letter ( reverse 'a'..'z' ) {
print "$letter\n";
}
Esto tambien incrementa bien "letter lists":
for ( 'aa'..'zz' ) {
print "$_ "; #
Imprimirá "aa ab ac ... zx zy zz"
}
Entrada Usuario
Capturar entradas del teclado, o entradas de STDIN en general -como las líneas conducidas a la entrada de nuestro script via alguna cosa como
cat file | perl_script
- es fácil; eso es para lo sirve que el "operador diamante" de Perl.
while ( <> ) { # Captura todo el
teclado o los conductos de entrada
print; # Imprime cada línea tan
largo como entrada exista
}
Lo anterior trabaja exactamente como "cat" -imprimirá toda la entrada conducida a el, hará "cat" a un archivo si está corriendo con el nombre de archivo usado como argumento, y aceptará ( y resonará) la entrada usuario mientras que presiones Ctrl-D or Ctrl-C. Eso también puede ser escrito de la siguiente forma:
print while <>;
para una mayor sintáxis "Perl". Nota que "<>" y "<STDIN>" están relacionados pero no son equivalentes:
print while <STDIN>;
responderá a el teclado y los conductos de entrada, pero no imprimirá el contenido de un archivo dado como un argumento. No he encontrado una situación en donde necesite esta función, así que simplemente uso "<>".
Si quieres la entrada usuario a una variable, Perl tambien hace esto fácilmente -pero hay un aspecto en el que necesitas ser cuidadoso:
$answer = <>; # Obtiene la entrada, la
asigna a una variableif ( $answer eq "y" ) {
print "Yes\n";
}
elsif ( $answer eq "n" ) {
print "No\n";
}
else {
print "No idea!\n";
}
El script anterior siempre imprimirá "No idea!" Hmm... se ve bien; ¿Cuál puede ser el problema?
El problema es que Perl captura cada cosa que le des. Así cuando tecleas "y", ¿Cuál es la siguiente tecla que presionas? ¡es "Enter" ! Así, la variable almacenada en $answer es NO "y", esto es "y\n" - la respuesta y el final de línea. ¿Cómo podemos trabajar con esto? Perl, por supuesto, tiene una función - una que debes usar siempre cuando obtienes la entrada usuario:
chomp ( $answer = <> );
"chomp" removerá el caracter de fin de línea, de la cadena a la que es
aplicado. También quitará EOLs de cada elemento del arreglo que recibe como argumento.
En la vieja versión Perl4, "chop" eliminaba el último caracter de un escalar
(o de los elementos de el arreglo) sin importar lo que fuera; está aún disponible por si
debes usarlo para tal propósito, pero para tomar la entrada usuario, use
"chomp" (también conocido, por los mensajes de error de Perl, como "safe
chop").
Ejercicios Para La Mente
Intente construir un par de scripts, tan solo para su propia educación y entretenimiento:
Un script que toma un número como entrada, e imprime "Hello!" muchas veces.
Un script que toma la hora actual (0-23) como entrada y dice "Good morning", "Dobriy den'", "Guten Abend", o "Buenas noches" como resultado. <grin>
Si implementas algo particulamente interezante, no dudes en mandarmelo para la siguiente parte de esta serie: obtendrás el crédito por escribirlo, lo analizaré gustosamente para ti, y los dos seremos micro-famosos y nos retiraremos a Belice en el proceso. <laugh>
No olvides que: tu línea shebang debe siempre contener "-w". Si no pides
ayuda a Perl con tus errores, estarás perdiendo mucho tiempo. ¡Deja a la computadora
hacer el trabajo difícil!
#!/usr/bin/perl -w
print "See you next month!"
Ben Okopnik
perl -we'print reverse split//,"rekcah lreP rehtona tsuJ"'
Referencias:
Páginas man relevantes de Perl(disponible en algún sistema pro-Perl-y configurado):
perl -
panorama
perlfaq - Perl FAQ
perltoc - doc
TOC
perldata - estructuras de datos
perlsyn -
sintáxis
perlop - operadores/precedencia
perlrun -
ejecución
perlfunc - funciones constructoras
perltrap - trampa para imprudentes perlstyle - estilo guía
"perldoc", "perldoc -q" y "perldoc -f"