• Publicidad

Sustituciones sobre dos archivos de entrada

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Sustituciones sobre dos archivos de entrada

Notapor sisifo80 » 2014-05-19 07:15 @344

Hola,

Quisiera saber si en Perl es posible trabajar con dos archivos de entrada simultáneamente para crear un archivo de salida.

Es decir, tengo varios archivos llamados ????_header.XML y varios archivos llamados ????_text.xml. Para cada par "_header.xml" y "_text.xml" quisiera crear un archivo .txt a partir de los datos de entrada de los dos archivos .xml (header y text).

Ese script de conversión estaría compuesto de varias órdenes de sustitución y otras cosas, pero lo que no sé es cómo decir en Perl (o en la consola de comandos) que algunas sustituciones las haga a partir de un archivo de entrada y otras sustituciones las haga a partir del otro archivo de entrada. Por supuesto, siempre podría crear dos script. Pero, ¿es posible hacerlo en uno solo?

Perdón por lanzar una pregunta tan general.

Gracias.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Publicidad

Re: Sustituciones sobre dos archivos de entrada

Notapor explorer » 2014-05-19 09:16 @428

Pues sí que se puede hacer. Cada vez que haces un readline() o pones el operador diamante (<>) estás leyendo una línea del archivo correspondiente, así que es cuestión de leer las líneas en el orden en que las necesites.

Otra opción es leer los dos archivos a memoria, guardarlos en array, y así se puede avanzar o retroceder por los contenidos de los dos archivos.

Una solución intermedia es la de usar Tie::File, que "enlaza" un array local con las líneas de un archivo. Se puede hacer otro nudo con el otro archivo, y así tienes dos array independientes.

En el hilo Sustituir datos de un archivo a otro encontrarás un ejemplo de lectura sincronizada entre dos archivos (se lee de cada vez una línea de cada archivo, se procesan, y el resultado se graba en un tercero).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Sustituciones sobre dos archivos de entrada

Notapor sisifo80 » 2014-05-19 10:26 @476

Muchas gracias, explorer.

Supongamos que estoy interesado en tu segunda opción (leer los dos archivos a memoria guardándolos en array). Supongamos que todos mis archivos de entrada (los que acaban en header.xml y los que acaban en text.xml) los guardo en una carpeta llamada "input". He probado lo siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3.  
  4. opendir IN, 'input';
  5. my @lines1 = grep { /header.xml$/ } readdir IN;
  6. my @lines2 = grep { /text.xml$/ } readdir IN;
  7. closedir IN;
  8.  
  9. for my $lines1 (@lines1) {
  10.   open IN, '<', "input/$lines1" || next;
  11.   open OUT, '>', "output/$lines1" || die "can't open file output/$lines1";
  12.   while(<IN>) {
  13.   #hacer toda una serie de operaciones
  14.   print OUT;
  15.   }
  16.   close OUT;
  17.   close IN;
  18. }
  19.  
  20. for my $lines2 (@lines2) {
  21.   open IN,  '<', "input/$lines2" || next;
  22.   open OUT, '>', "output/$lines2" || die "can't open file output/$lines2";
  23.   while(<IN>) {
  24.   #hacer toda una serie de operaciones
  25.   print OUT;
  26.   }
  27.   close OUT;
  28.   close IN;
  29. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Pero lo que obtengo en la carpeta "output" es simplemente los archivos "...header.xml" con las modificaciones correspondientes. Y lo que yo querría es un archivo de salida por cada par "...header.xml" + "...text.xml" que conservase las modificaciones hechas en ambos archivos de entrada. ¿Es posible con la estrategia que estoy siguiendo?

He conseguido que me lea los dos tipos de archivos de entrada:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3.  
  4. opendir IN, 'input';
  5. my @lines1 = grep { /header.xml$/ } readdir IN;
  6. closedir IN;
  7.  
  8. for my $lines1 (@lines1) {
  9.   open IN, '<', "input/$lines1" || next;
  10.   open OUT, '>', "output/$lines1" || die "can't open file output/$lines1";
  11.   while(<IN>) {
  12.   #hacer toda una serie de operaciones
  13.   }
  14.   close OUT;
  15.   close IN;
  16. }
  17.  
  18. opendir IN, 'input';
  19. my @lines2 = grep { /text.xml$/ } readdir IN;
  20. closedir IN;
  21.  
  22. for my $lines2 (@lines2) {
  23.   open IN, '<', "input/$lines2" || next;
  24.   open OUT, '>', "output/$lines2" || die "can't open file output/$lines2";
  25.   while(<IN>) {
  26.   #hacer toda una serie de operaciones
  27.   print OUT;
  28.   }
  29.   close OUT;
  30.   close IN;
  31. }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Pero ahora el problema es que las modificaciones realizadas no se imprimen todas en un único archivo de salida, sino que se crea una archivo de salida ...header.xml y otro ...text.xml, cada uno con sus respectivas modificaciones.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Re: Sustituciones sobre dos archivos de entrada

Notapor explorer » 2014-05-19 15:11 @674

Lo que has hecho hasta ahora es leer los nombres de los archivos y guardarlos en array, pero no el contenido de los mismos.

¿Puedes publicar un ejemplo -mínimo- de lo que quieres hacer?
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Sustituciones sobre dos archivos de entrada

Notapor sisifo80 » 2014-05-19 17:10 @757

Mis disculpas. La verdad es que mi explicación no fue muy clara. Lo vuelvo a intentar.

Tengo dos tipos de archivos de entrada. Los archivos del tipo1 se llaman de la siguiente manera:

0001_header.xml
0002_header.xml
0003_header.xml
...


Los archivos del tipo2 se llaman de la siguiente manera:

0001_text.xml
0002_text.xml
0003_text.xml
...


De los archivos tipo1 necesito imprimir el contenido de la etiqueta <title></title>.
De los archivos tipo2 necesito varias cosas, pero para simplificar diremos que necesito imprimir el contenido de la etiqueta <text></text>.

Todos estos archivos están guardados en una carpeta llamada input/.

El objetivo es que en la carpeta llamada output/ se creen archivos .txt (0001.txt, 0002.txt, 0003.txt, ...) que muestren el resultado conjunto de ambas impresiones. Por ejemplo:

Imaginemos que en el archivo "0001_header.xml" se incluye la siguiente información:

<title>Esto es un título</title>

Imaginemos que en el archivo "0001_text.xml" se incluye la siguiente información:

<text>Esto es texto</text>

El archivo creado 0001.txt debería contener:

TITULO: esto es un título
TEXTO: Esto es texto


Propuesta 1:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2.     use warnings;
  3.      
  4.     opendir IN, 'input';
  5.     my @lines1 = grep { /header.xml$/ } readdir IN;
  6.     closedir IN;
  7.      
  8.     for my $lines1 (@lines1) {
  9.       open IN, '<', "input/$lines1" || next;
  10.       open OUT, '>', "output/$lines1" || die "can't open file output/$lines1";
  11.           print OUT "TITULO: ";
  12.       while(<IN>) {
  13.       if (/<title>(.+?)<\/title>/) {print OUT "$1\n"};
  14.       }
  15.       close OUT;
  16.       close IN;
  17.     }
  18.      
  19.     opendir IN, 'input';
  20.     my @lines2 = grep { /text.xml$/ } readdir IN;
  21.     closedir IN;
  22.      
  23.     for my $lines2 (@lines2) {
  24.       open IN, '<', "input/$lines2" || next;
  25.       open OUT, '>', "output/$lines2" || die "can't open file output/$lines2";
  26.           print OUT "TEXTO: ";
  27.       while(<IN>) {
  28.       if (/<text>(.+?)<\/text>/) {print OUT "$1\n"};
  29.       }
  30.       close OUT;
  31.       close IN;
  32.     }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


En este caso no sé cómo hacer que los archivos de salida creados sean txt y que combinen en un único txt ambas modificaciones (ambos print).

Otra opción que probé fue crear una variable que incluya el contenido de las dos entradas, para poder trabajar a partir de ahí:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use strict;
  2. use warnings;
  3.  
  4. my $content;
  5. local $/ = undef;
  6. open(IN, "<0001_header.xml");
  7. $content = <IN>;
  8. close(IN);
  9. open(IN, "<0001_text.xml");
  10. $content .= <IN>;
  11. close(IN);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Pero en este caso no sé cómo aplicar el script a varios archivos a la vez para crear los respectivos .txt.
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354

Re: Sustituciones sobre dos archivos de entrada

Notapor explorer » 2014-05-20 06:34 @315

Sí, se puede hacer lo segundo, pero algo que falta en los programas es la "sincronización". Quiero decir que hay que fijarse que estamos procesando los archivos 00001, y luego los 00002, y así. Si los lees tal cual llegan por el readdir(), te arriesgas a recibirlos desordenados (dependerá de cómo estén grabados en el sistema de archivos).

Entonces, lo que se puede hacer es: leemos los nombres de todos los archivos header. Por cada uno de ellos, le sacamos el número, y ese número lo usamos para localizar el archivo text correspondiente y grabar el resultado en un .txt.

Algo así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4. use File::Slurp;
  5.  
  6. my @archivos_header = <*_header.xml>;                   # leemos los nombres de todos los archivos header
  7.  
  8. for my $archivo_header (@archivos_header) {             # para cada uno de ellos
  9.  
  10.     my($indice)= $archivo_header =~ /^(\d+)/;           # le sacamos el número
  11.    
  12.     my $header = read_file($archivo_header);            # leemos el archivo header
  13.     my $text   = read_file($indice . '_text.xml');      # y su correspondiente text
  14.  
  15.     my $salida;                                         # aquí almacenaremos el contenido del archivo de salida
  16.    
  17.     ## header
  18.     my($titulo)= $header =~ m{<title>(.+?)</title>};    # extracción del título
  19.     if($titulo) {                                       # si lo hay
  20.         $salida .= "TITULO: $titulo\n";                 # lo agregamos a la $salida
  21.     }
  22.    
  23.     ## text
  24.     my($texto) = $text   =~ m{<text>(.+?)</text>};      # extracción del texto
  25.     if($texto) {                                        # si lo hay
  26.         $salida .= "TEXTO: $texto\n";                   # lo agregamos a la $salida
  27.     }
  28.    
  29.     open my $OUTPUT, '>', "$indice.txt";                # grabación del resultado
  30.     print   $OUTPUT $salida;
  31.     close   $OUTPUT;
  32. }
  33.  
  34. __END__
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Sustituciones sobre dos archivos de entrada

Notapor sisifo80 » 2014-05-21 04:57 @248

Muchas gracias, explorer. Tu script funciona perfectamente y, gracias a las explicaciones que incluiste, lo puedo utilizar como base para futuros scripts que necesito. ¡Mil gracias!
sisifo80
Perlero nuevo
Perlero nuevo
 
Mensajes: 32
Registrado: 2013-11-20 07:30 @354


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 21 invitados

cron