[Q] regular expressions

Ernesto Hernández-Novich emhn at telcel.net.ve
Wed Jul 26 13:21:17 CDT 2000


On Wed, 26 Jul 2000, you wrote:
> El siguiente script hace, lo que pretendo hacer: me quita los palitos
> despues del palito nro. 10.
> 
> 024|09|27.8347|-070|28.3004|Sun|Dec|31|00:00:00|1989|07-FEB-00|12:33
> 025|10|05.4527|-069|41.9270|Sun|Dec|31|00:00:00|1989|07-FEB-00|15:43
> NEW-1|10|19.6010|-066|49.6690||Jan|03|00:00:00|2000|BOTEQUIN
> NEW-10|10|19.3510|-066|50.5760||Jan|03|00:00:00|2000|TANQUE|DE|AGUA
> 
>    $count = 0;
>    s{(\|)}{
>           ++$count > 10  #  linea 25
>              ? "$1{1} "
>              : $1
>         }gex;
> 
> Cada vez que se substituye un palito por un espacio sale:
> 
> Use of uninitialized value at gd22w_t.pl line 25, <R> chunk 38.
> Acaso la line 23 no tiene efecto?
> El chunk x aparentemente tiene que ver con el nro. de la linea de
> archivo
> con el qual esta trabajando.

La línea 23 tiene efecto, pero el error no es en relación a $count sino a lo
que tienes como resultado del ?: que está indefinido.

El error se debe al $1{1}. $1{1} es pedir el elemento con clave '1' del hash
%1 el cual, por supuesto, no existe y por tanto no pone nada. Este "nada" se
concatena con espacio en blanco y el programa "funciona" pero tiene un bug
oscuro :-).

Dicho bug, corregido, quedaría como

s/(\|)/(++$count > 10) ? " " : $1/gex;

y funciona bien. Sin embargo, hay una solución más práctica, clara, y sobre
todo _rápida_; la solución se basa en lo siguiente:

# Quito el \n

chomp;

# Rompo (split) por "|" esto genera una _lista_ con todos los campos.
# @diez[0..9] genera una _lista_ de 10 elementos y
# @resto es una _lista_ sin tamaño definido, entonces

(@diez[0..9], at resto) = split /\|/;

# Consecuencia: las primeras diez columnas quedan en $diez[0] hasta $diez[9] y
# @resto se traga todas las columnas que quedan.
#
# join(" ", at resto) une las columnas más allá de la diez con " " en un escalar
# y entonces

join("|", at diez[0..9],join(" ", at resto));

# Consecuencia: las primeras diez columnas quedan unidas con "|" y el resto,
# que ya estaba unido con " " se pone al final.

Esta segunda solución es casi el doble de rápida que con expresiones
regulares. Puedes compararlas usando el módulo Benchmark de Perl, con el
ejemplo a continuación:

#!/usr/bin/perl -w
# datos es un archivo con los datos de prueba

use Benchmark;

timethese(10000, {
  'withjoin'   => sub {
                        open(D,"datos");
                        while (<D>) {
                          chomp;
                          (@diez[0..9], at resto) = split /\|/;
                          join("|", at diez[0..9],join(" ", at resto));
                        }
                        close(D);
                      },
  'withregexp' => sub {
                        open(D,"datos");
                        while (<D>) {
                          $count = 0;
                          s/(\|)/(++$count > 10) ? " " : $1/gex;
                        }
                        close(D);
                      }
 } );

Al ejecutarlo tienes una salida como

Benchmark: timing 10000 iterations of withjoin, withregexp...
  withjoin:  9 wallclock secs ( 3.80 usr +  0.42 sys =  4.22 CPU)
withregexp: 16 wallclock secs ( 7.90 usr +  0.45 sys =  8.35 CPU)

Tu solución, aunque válida, está planteada desde el paradigma de programación
imperativa (o procedural), el cual tiene limitaciones de expresividad para
operaciones de aplicación iterativa de funciones (precisamente lo que tu
quieres hacer). Mi solución está planteada desde el paradigma de programación
funcional, el cual descansa sobre la composición de funciones con iteración
implícita (como split y join). Perl provee ambos paradigmas, todo el secreto
está en aprovechar el más adecuado para cada problema...

P.S. Muchos problemas como este se resuelven más rápido y mejor pensando en
Lisp o ML, en lugar de pensar en C, Modula o (yeech!) Basic.

There's more than one way to do it!
-- 
Ernesto Hernández-Novich - Running Linux 2.2.16 i686 - Unix: Live free or die!
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS d+(-) s+: a C+++$ UBLAVHIOSC++++$ P++++$ L+++$ E- W+ N++ ?o ?K w--- O- M- V
PS+ PE Y+ PGP>++ t+ 5 X+ R* tv+ b++ DI+++$ D++ G>++ e++ h+ r+ y++
-----END GEEK CODE BLOCK-----

------------------------------------------------------------------------
Enviar e-mail a <majordomo at pm.org> colocando en el cuerpo:
"UNSUBSCRIBE caracas-pm-list" para desuscribirse.
"INFO caracas-pm-list" para conocer las reglas de etiqueta.
------------------------------------------------------------------------



More information about the caracas-pm mailing list