next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Utilizando score Sup: RecDescent Ant: Las Directivas skip y Err: Si hallas una errata ...

Las directivas rulevar y reject

En los apuntes de Conway del ``Advanced Perl Parsing'' realizado durante el Deutscher Perl-Workshop 3.0 en el año 2001 se plantea la siguiente variante del problema de los valores separados por comas: los campos no están delimitados por dobles comillas y el separador es aquél que separa la línea en un mayor número de elementos, o lo que es lo mismo, aquél separador (de entre un grupo fijo [:,\t]) que se repite mas veces en la línea. Por ejemplo, la línea:
a:1,b:2,c:3,d
se separará por comas produciendo la lista ["a:1", "b:2","c:3","d"], pero la línea
a:1,b:2,c:3:d
se separará mediante el carácter dos puntos produciendo la lista ["a","1,b", "2,c","3","d"].

Para resolver el problema se declaran dos variables max y $maxcount locales al método asociado con la variable sintáctica line que reconoce la categoría gramatical línea. Para declarar tales variables se usa la directiva rulevar.

La otra directiva que se usa es reject, la cuál hace que la producción falle (exactamente igual que si la acción hubiese retornado undef). La estrategia consiste en almacenar en, separador por separador llevar en $maxcount el máximo número de items en que se descompone la línea y en $max la referencia al array anónimo ``ganador''.

 #!/usr/local/bin/perl5.8.0 -w
 use strict;
 use Parse::RecDescent;
 use Data::Dumper;
 
 #$::RD_TRACE = 1;
 my $grammar = q{
   line : <rulevar: $max>
   line : <rulevar: $maxcount = 0>
   line :  <leftop: value ',' value> 
            { $maxcount = @{$item[1]}; $max = $item[1]; 
              print "maxcount[,] = $maxcount\n"; }
            <reject>
        | <leftop: datum ':' datum> 
            { if (@{$item[1]} > $maxcount) { 
                $maxcount = @{$item[1]}; $max = $item[1]; } 
              print "maxcount[,:] = $maxcount\n";
            }
            <reject>
        |  <leftop: field ";" field> 
            { if (@{$item[1]} > $maxcount) { 
                $maxcount = @{$item[1]}; $max = $item[1]; } 
              print "maxcount[,:;] = $maxcount\n";
            }
            <reject>
        | { $return = $max; }
         
   value: /[^,]*/ 
   datum: /[^:]*/ 
   field: /[^;]*/ 
 };
 
 my $parse = Parse::RecDescent->new($grammar);
 my $line;
 while ($line = <>) {
   print "$line\n";
   my $result = $parse->line($line);
   if (defined($result)) { print Dumper($result); }
   else { print "Cadena no válida\n"; }
 }
Probemos el código con el siguiente fichero de entrada:
 cat file3.txt
1:2:3,3:4;44
1,2:3,3:4;44
1;2:3;3:4;44
He aqui una ejecución:
$ ./maxseparator.pl file3.txt
1:2:3,3:4;44

maxcount[,] = 2
maxcount[,:] = 4
maxcount[,:;] = 4
$VAR1 = [ '1', '2', '3,3', '4;44 ' ];
1,2:3,3:4;44

maxcount[,] = 3
maxcount[,:] = 3
maxcount[,:;] = 3
$VAR1 = [ '1', '2:3', '3:4;44 ' ];
1;2:3;3:4;44

maxcount[,] = 1
maxcount[,:] = 3
maxcount[,:;] = 4
$VAR1 = [ '1', '2:3', '3:4', '44 ' ];


next up previous contents index PLPL moodlepserratamodulosperlmonksperldocapuntes LHPgoogleetsiiullpcgull
Sig: Utilizando score Sup: RecDescent Ant: Las Directivas skip y Err: Si hallas una errata ...
Casiano Rodríguez León
2012-05-22