"tierra, luna",1,"marte, deimos",9.374
la extensión consiste en admitir que el separador puede cambiar
entre líneas y en los campos de una línea, pudiendo ser
no sólo la coma sino también un tabulador o el carácter dos puntos.
El problema está en que los separadores dentro de las cadenas
no deben confundirnos. Por ejemplo, la coma en
"tierra, luna"
no debe ser interpretada como
un separador.
He aqui una solución usando RD:
1 #!/usr/local/bin/perl5.8.0 -w 2 use strict; 3 use Parse::RecDescent; 4 use Data::Dumper; 5 6 my $grammar = q{ 7 line : <leftop: value sep value> 8 value: /"([^"]*)"/ { $1; } 9 sep : <skip:""> /[:,\t]/ 10 }; 11 12 my $parse = Parse::RecDescent->new($grammar); 13 14 my $line; 15 while ($line = <>) { 16 print "$line\n"; 17 my $result = $parse->line($line); 18 print Dumper($result); 19 }
La directiva <skip>
usada en la línea 9
permite redifinir lo que el analizador entiende
por ``blancos'': los símbolos sobre los que saltar. Por defecto
el tabulador es un ``blanco''. En este ejemplo, cuando estamos
reconociendo un separador no queremos que sea así. La directiva
<skip:"">
hace que ningún símbolo sea considerado como blanco.
La directiva usada en la línea 7 <leftop: value sep value>
especifica una lista asociativa a izquierdas de elementos de tipo value
separados por elementos del lenguaje denotado por sep
.
El valor retornado es un array anónimo conteniendo
la lista de elementos. En general, si el separador es especificado
como una cadena, la directiva no retorna
el separador como parte de la lista. Por ejemplo,
en el código:
list: '(' <leftop: list_item ',' list_item> ')' { $return = $item[2] }
el valor devuelto es una referencia a la lista, la cual no incluye las comas. Sin embargo, cuando el separador viene dado por una variable sintáctica o bien por medio de una expresión regular, las distintas apariciones del separador se incluyen en la lista devuelta. Este es el caso en nuestro ejemplo.
Veamos primero el fichero de entrada para la ejecución:
$ cat file.txt "xx":"yyy":"zzz" "xx","yyy","zzz" "xx" "yyy" "zzz" "xx" "yyy","zzz" "xx":"yyy","zzz" "x:x":"y,y","z zz" "x:x":"y,y","z zz"."ttt"La última fila usa el punto como separador del último campo. La ejecución de
Dumper($result)
en la línea 18
nos muestra las listas formadas:
$ ./commaseparated.pl file.txt "xx":"yyy":"zzz" $VAR1 = [ 'xx', ':', 'yyy', ':', 'zzz' ]; "xx","yyy","zzz" $VAR1 = [ 'xx', ',', 'yyy', ',', 'zzz' ]; "xx" "yyy" "zzz" $VAR1 = [ 'xx', ' ', 'yyy', ' ', 'zzz' ]; "xx" "yyy","zzz" $VAR1 = [ 'xx', ' ', 'yyy', ',', 'zzz' ]; "xx":"yyy","zzz" $VAR1 = [ 'xx', ':', 'yyy', ',', 'zzz' ]; "x:x":"y,y","z zz" $VAR1 = [ 'x:x', ':', 'y,y', ',', 'z zz' ]; "x:x":"y,y","z zz"."ttt" $VAR1 = [ 'x:x', ':', 'y,y', ',', 'z zz' ];La última entrada
"x:x":"y,y","z zz"."ttt"
muestra como el analizador
se detiene en la cadena máximal "x:x":"y,y","z zz"
que pertenece
al lenguaje.
"x:x":"y,y","z zz"
que puede aceptar. Si queremos que la conducta sea de rechazo,
se puede hacer que sea la línea completa la que se empareje.
Escriba una nueva versión del programa anterior que recoja esta
especificación.