jueves, 22 de agosto de 2013

Ocultar los primeros N digitos o los últimos con una expresion regular

Ocultar los primeros caracteres de una cadena

Supongamos que queremos ocultar los primeros 12 caracteres de una cadena que tiene más de 11 caracteres, cambiando esos caracteres por letras x:
$cadena= 'abcdefghijklmnopq';
$cadena =~ s/^............/xxxxxxxxxxxx/;
print 'Cadena: ' . $cadena;
xxxxxxxxxxxxmnopq

Ocultar los últimos caracteres de una cadena

Supongamos que queremos ocultar los ultimos 4 caracteres de una cadena que tiene más de 3 caracteres, cambiando esos caracteres por letras x:
$cadena= 'abcdefghijklmnopq';
$cadena =~ s/....$/xxxx/;
print 'Cadena: ' . $cadena;
abcdefghijklmxxxx


lunes, 15 de julio de 2013

Mermelada cítricos y kiwi

Mi mermelada de kiwis y cítricos


Dicen que programar es como escribir una receta de cocina, así que hoy vamos a cocinar una mermelada.

Dejar los cítricos (naranjas, mandarinas y al menos un limón) en agua por 3 días, cambiando el agua cada 12 horas.

Cortar por la mitad para sacar las semillas...

Y volver a cortar para pasarlos por la licuadora hasta que quede en un punto medio entre todo triturado y pedacitos de cáscara visible.


Así quedaron los cítricos licuados:



Ponemos a hervir un poco de agua y le echamos el azúcar con los cítricos en su jugo para cocerlos a fuego medio por una hora y media.

Revolvemos cada 15 minutos, especialmente por el final.


Unos 20 minutos antes de finalizar echamos los kiwis cortados en rodajas.

Cúando está listo? esto es relativo, la forma de comprobarlo es que al mover la mermelada conserve cierta ligereza y no quede muy espesa.




Algunos le echan algo de romero o canela. Otros ponen primero las partes más gruesas del triturado a calentar y a la mitad de la cocción colocan el azúcar con el jugo. Hay que probar combinaciones y ver cuál queda más a nuestro gusto.

Para conservar en frascos: meter la mermelada muy caliente en los mismos, apretar la tapa y dar vuelta para que se haga vacío, así se conserva más tiempo.

Lo peor de hacer la mermelada es limpiar la cocina, pero seamos ordenados y vayamos limpiando a medida que la realizamos, como cuando hacemos el código sucio para que funcione y lo depuramos de a poco y lo limpiamos.
¡Buena cocina!


lunes, 27 de mayo de 2013

Corolario I


Un juego en Perl

Como corolario de la Parte I de "Perl for newbies" vamos a programar un juego muy simple. Se trata de adivinar qué número está pensando la computadora. Se le pide al usuario que adivine el número y le informamos si acertó o si su número es mayor o menor. Manos a la obra!

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero',"\n";
my $miNumero= 5;
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   print 'Dime que numero estoy pensando',"\n";
   my $numero= <>;
   chomp($numero);
   if ($miNumero==$numero){
      print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!',"\n";
   } elsif($miNumero<$numero) {
      print 'No. Mi numero es menor que ', $numero, "\n";
   } else {
      print 'No. Mi numero es mayor que ', $numero, "\n";
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Las posibles salidas del programa son:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
5
Si! Acertaste! Mi numero es el 5!!!
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
9
No. Mi numero es menor que 9
Gracias por jugar conmigo
---------------------------------------------------------------------------

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero
Quieres adivinar mi numero? (si/no)
no
Esta bien, no quieres adivinar mi numero
Gracias por jugar conmigo
---------------------------------------------------------------------------
Usamos el operador x para imprimir una cantidad fija de caracteres, en este caso '*' y '-'. También usamos <> para recibir la respuesta del usuario, chomp() para limpiarla, print para enviarle mensajes y la estructura de control if para tomar decisiones según el valor ingresado. El problema es que el usuario puede arriesgar una sola vez el valor, además ya sabemos que el número elegido será el 5 así que el juego se torna algo monótono y aburrido. Deberíamos darle al usuario un número distinto cada vez y la oportunidad de adivinarlo con cierta cantidad de intentos, digamos 3. Hagamos las modificaciones para que quede mejor este juego.

Modificaciones

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
my $miNumero;
if ('si'eq@respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumeroo \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Usamos la función rand() para obtener un número aleatorio entre 0 y el argumento, en este caso 10, y aunque el número aleatorio podría ser el 0 nunca va a ser 10, pero como son números de coma flotante también usamos la función int() para que nos deje la parte entera del número. Usamos un bucle for que va de 1 a 3 gracias al operador .. que nos devuelve un arreglo de números consecutivos. Usamos last para salir del bucle cuando el usuario adivina el número. Pero el programa no funciona como queremos. Cuando el usuario escribe 'si' el programa termina sin informarnos nada anormal. Para que Perl nos dé más información sobre los posibles errores tenemos que usar dos pragmas muy útiles: strict y warnings. Veamos la diferencia. Cuando agregamos al comienzo del programa
use strict;
use warnings;
Nos informa lo siguiente:
Global symbol "@respuesta" requires explicit package name at adivina2.pl
Global symbol "$miNumeroo" requires explicit package name at adivina2.pl
Hay dos errores de tipeo, primero el @ en la variables $respuesta, luego la 'o' repetida al final de $miNumero. Corregimos y nos dice lo siguiente:
"my" variable $miNumero masks earlier declaration in same scope at adivina2.pl
Parece que declaramos dos veces la misma variable. Borramos la segunda declaración que es la incorrecta en este caso y corremos el programa. Funciona!
use warnings;
use strict;

print '*'x78;
print "\n";
print 'Adivina mi numero';
print "\n";
print '*'x78;
print "\n";

print 'Estoy pensando un numero del 0 al 9',"\n";
my $miNumero= int(rand(10));
print 'Quieres adivinar mi numero? (si/no)',"\n";
my $respuesta= <>;
chomp($respuesta);
if ('si'eq$respuesta) {
   for my $i (1..3){
      print 'Dime que numero estoy pensando',"\n";
      my $numero= <>;
      chomp($numero);
      if ($miNumero==$numero){
         print 'Si! Acertaste! Mi numero es el ', $miNumero, '!!!', "\n";
         print "Y usaste $i intentos \n";
         last;
      } elsif($miNumero<$numero) {
         print 'No. Mi numero es menor que ', $numero, "\n";
         if (3==$i){ print  "Mi numero era el $miNumero \n"; }
      } else {
         print 'No. Mi numero es mayor que ', $numero, "\n";
         if (3==$i){ print "Mi numero era el $miNumero \n"; }
      }
   }
} else {
   print 'Esta bien, no quieres adivinar mi numero',"\n";
}

print 'Gracias por jugar conmigo',"\n";
print '-'x78;
print "\n";

Y esta es mi jugada:

***************************************************************************
Adivina mi numero
***************************************************************************
Estoy pensando un numero del 0 al 9
Quieres adivinar mi numero? (si/no)
si
Dime que numero estoy pensando
7
No. Mi numero es menor que 7
Dime que numero estoy pensando
2
No. Mi numero es mayor que 2
Dime que numero estoy pensando
4    
No. Mi numero es mayor que 4
Mi numero era el 5  
Gracias por jugar conmigo
---------------------------------------------------------------------------

Más modificaciones

Podríamos seguir modificando el programa. Por ejemplo dejar que el usuario elija cuantos intentos puede tener, o que luego de un juego el usuario pueda seguir jugando en vez de terminar el programa, o que el programa elija un número de 2 cifras, o que en vez de elegir un número aleatorio sea una letra aleatoria. Cómo podemos asignar una letra aleatoria a una variable?
my $letra= ('a'..'z')[rand(26)];






martes, 5 de junio de 2012

Una introducción agradable a Moose


Lo que sigue es la versión en español del artículo A gentle introduction to Moose escrita por Jay Kuri en el 2009.


Perl, desde el lanzamiento de su versión 5 en 1994, tiene las características de un lenguaje orientado a objetos. Pero estas características OO siguen siendo algo así como un "hágalo Usted mismo", con el clásico estilo de Perl, ofreciendo un mínimo de apoyo integrado en el lenguaje y el resto se deja a cargo de los demás. 

La principal ventaja de este estilo "hágalo Usted mismo" es que el lenguaje impone muy pocas restricciones sobre la manera de hacer las cosas. Por otro lado tiene la desventaja de ser algo intimidante con los novatos. Por lo bueno y lo malo, se ha vuelto familiar.

Otra ventaja es que las características tienen la libertad de evolucionar, por no estar sujetas por el lenguaje algunos programadores muy inteligentes tuvieron la libertad de explorar formas de hacer las cosas de maneras que no estaban preconcebidas. Moose es el resultado de ésta exploración y rápidamente se convirtió en el estandar defacto para la POO en Perl. Hoy vamos a explorar las bases de la creación y manipulación de objetos en Moose.

En la convencional Programación Orientada a Objetos en Perl hay tres cosas principales que necesitan hacerse. Estas son:
  1. Creación de objetos
  2. Atributos y métodos de acceso
  3. Herencia
Tomaremos un rápido exámen alrededor de estas cuestiones y las compararemos con la técnica Perl y la de Moose.


Creación de objetos
En puro Perl, la forma de crear un objeto es crear una referencia a una variable y luego "bendecirla" con una clase. Podemos hacer esto con cualquier tipo de variable, pero lo más común es usar una referencia a un hash. Esto se hace generalmente en una subrutina 'new':
package FooClass;

  sub new {
      my $class = shift;
      my $foo = {};
      bless $foo, 'FooClass';
      return $foo;
  }

Esto devuelve un objeto. Hay algo más aún. La forma Moose de hacer esto es algo más sencilla:
  package FooClass;
  use Moose;

Eso es todo. Moose crea la subrutina new() por nosotros. Si la clase tiene atributos, Moose también se encargará de gestionarlos basándose ​​en los argumentos que se pueden colocar.
Crear una instancia de una clase sigue la misma convención en un objeto de Moose como un objeto de puro Perl: simplemente llamar a new() en la clase. Moose, sin embargo, permite pasar los valores iniciales de sus atributos en la llamada. Por ejemplo:
  FooClass->new( name => 'bob' );
Este es un poco de funcionalidad útil y gratuita que nos brinda el uso de Moose.


Atributos y métodos de acceso
En Perl, nuestro objeto es (muy a menudo) un hash y sus atributos son simplemente miembros de ese hash. De nuevo a menudo, tales atributos se acceden directamente:
  $foo->{name};
Este generalmente está mal visto, ya que proporciona muy poca estructura y hace fácil declarar mal accidentalmente los atributos. $foo-> {naem} puede ser un error muy difícil de encontrar. La "mejor práctica" generalmente consiste en crear las subrutinas de acceso para las variables, lo que limita a los que utilizan el objeto para trabajar con los atributos que hay creados. (Los geeks OO se refieren a esto como "encapsulación"). El problema es que en Perl OO lo debemos crearlas nosotros mismos:
   sub name {
        my $self = shift;
        if( @_ ) {
            $self->{'name'} = $_[0];
        }
        return $self->{'name'};
    }

Se trata de una gran cantidad de código sólo para escribir los setter/getter del objeto. En puro Perl hay un módulo de CPAN nacido para hacer esto más fácil. Class::Accessor construye estos métodos por nosotros:
  package FooClass;
  use base qw(Class::Accessor);
  FooClass->mk_accessors(qw(name age));

Class::Accessor crea el método new por nosotros. Esto es claramente mejor que hacerlo a mano. Ahora es prácticamente imposible crear accidentalmente atributos o acceder a los equivocados. Hay una cosa que no hace bien. No le impide de ninguna manera poner basura en los atributos. Esto es perfectamente legal:
  $foo = FooClass->new();
  $foo->name(192);
  $foo->age('magdalena');

Moose, por el contrario, no sólo hace lo que Class::Accessor, sino que añade la comprobación de tipos (y algunas otras cosas). El mismo objeto creado con Moose:
  package FooClass;
  use Moose;
  has 'name' => (
    is => 'rw',
    isa => 'Str'
  );

  has 'age' => (
    is => 'rw',
    isa => 'Int'
  );
  1;

Lo anterior proporciona el mismo name() y age() que estamos acostumbrados. Pero si tratamos de establecer la edad como 'magdalena' ahora vamos a obtener un error. Por otro lado también tenemos la capacidad de decir esencialmente "este atributo no se puede cambiar después de crear el objeto". Entre otras cosas, el sistema de atributos y de control de tipos de Moose es increíblemente flexible y merece su propio tutorial dedicado.


Herencia
La herencia en programación orientada a objetos está diseñada para permitir la especialización de una clase. El ejemplo clásico es que se puede tener una clase Figura que puede proporcionar un cierto grado de funcionalidad, y cuando se necesita una clase Cuadrado se puede heredar de Figura y añadir sólo el código que hace particular al Cuadrado. En Perl "puro" OO podríamos hacer esto:
  package Cuadrado;
  @ISA = ("Figura");
  # el resto de la clase Cuadrado

Perl tiene la inteligencia para buscar los métodos que no encuentra en la clase Cuadrado en las clases definidas en @ISA. Funciona bien, pero no es muy intuitivo. Moose tiene herencia también, y lo hace más evidente diciendo:
  package Cuadrado;
  use Moose;
  extends 'Figura';
  # el resto de la clase Cuadrado

Bastante sencillo


Otras cosas de Moose
Moose no hace nada que no se pueda hacer con Perl OO. Moose se basa en las mismas características OO soportadas por el lenguaje Perl. Se ocupa, sin embargo, de una enorme cantidad de trabajo que de lo contrario tendríamos que hacer nosotros mismos, dándole la libertad para trabajar en su "nueva" funcionalidad en lugar de reinventar la rueda una vez más.

En este artículo he mostrado cómo hacer las cosas "normales" de Perl OO con Moose. En este punto, usted sabe cómo hacer uso de la programación orientada a objetos básica y podría comenzar a reemplazar sus enrolladas clases hechas a mano por otras construidas con Moose.

Moose, sin embargo, es más que un poco de sintaxis inteligente y algunos ahorros de tiempo. Moose tiene algunas características adicionales que lo hacen realmente increíble para trabajar con él. Sólo voy a referirme a ellas aquí, ya que requeriría un libro entero para cubrirlas adecuadamente. Algunas de las características disponibles con Moose son las siguientes: 
  • Metadatos de la clase: La posibilidad que tiene su código de examinar la estructura de sus objetos.
  • Coerción: La capacidad de convertir los valores de un tipo a otro cuando sea necesario.
  • Modificadores de métodos: La capacidad de agregar código que se ejecuta antes, después o alrededor de un método existente.
  • Roles: La capacidad de agregar funcionalidad predefinida a las clases sin usar herencia.
Hay muchas otras que vale la pena investigar también. Los roles son especialmente interesantes y proporcionan una flexibilidad que no tiene precedentes en casi cualquier lenguaje orientado a objetos. También digno de mención son las extensiones de Moose que proporcionan una funcionalidad incluso más allá de Moose estándar.

Para obtener más información sobre Moose, eche un vistazo a la documentación. Para ver más en detalle Moose vs Perl OO, eche un vistazo a la versión "sin azúcar" del manual.

También puede consultar la página de inicio de Moose. Por último, he comenzado una lista de "Trampas de Moose" en Catalyzed Wiki para rastrear algunas de las partes más difíciles de Moose que he encontrado. Siéntase libre de agregar las propias, a medida que descubre los placeres de usar Moose.