• Publicidad

Interpretar archivo de texto plano

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

Interpretar archivo de texto plano

Notapor reLlene » 2012-11-21 09:05 @420

Después de un merecido(?) descanso vacacional, me reincorporo a esta comunidad nuevamente y con un embrollo entre manos. Bueno, no sé si para exagerarlo tanto. ¡je,je!

Hasta el momento sólo había interpretado archivos CSV y en esta oportunidad necesito interpretar un texto que se me presenta en un formato particular. Digo se me presenta porque se trata de un reporte de una compañía de tarjetas indicando aquellas cuentas que fueron bien imputadas y aquellas que fueron rechazadas, o bien modificadas.

Cómo verán en el adjunto que dejo a continuación, podrán notar que se divide en hojas (hoja 1, luego hoja 11, luego otra hoja 11) pero como no "respeta" nada deseché la idea de encarar por allí... Sin embargo parece prudente, al menos en mi humilde opinión, dividirlo en bloques y la referencia de éstos ser "cuotas aceptadas", "cuotas rechazadas" y "cuotas modificadas" por último y luego trabajar con cada uno de estos bloques, ya sea... si cuentan (por delante de las cuentas) con un CICLO (notar que el primero es el CICLO 0 y al final se TOTALIZA, luego viene el CICLO 1 y se vuelve a TOTALIZAR más abajo...) o no, si cuentan (por delante de las cuentas) con un "0"...

Repito, me gustaría poder agrupar cada uno de estos estados (aceptadas, rechazadas, modificadas) así que ¡¡¡bienvenida cualquier ayuda que me puedan brindar!!! :D
Última edición por reLlene el 2012-11-21 10:34 @482, editado 1 vez en total
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Publicidad

Re: Interpretar archivo de texto plano

Notapor reLlene » 2012-11-21 10:59 @499

¡¡Aquí lo adjunto!!
Adjuntos
reporte_ameex.txt
report
(31.63 KiB) 59 veces
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Interpretar archivo de texto plano

Notapor explorer » 2012-11-21 15:08 @672

Bueno, ahora lo que hay que hacer es analizar el archivo de texto y ver qué regularidades podemos encontrar.

Vemos que las hojas tienen una cabecera, un cuerpo y un pie de página. El pie de página parece que siempre es el mismo, así que podríamos tomarlo como separador entre hojas.

La cabecera es ligeramente distinta entre las tres opciones. Y el cuerpo es completamente distinto, aunque tiene la ventaja de comenzar siempre en las mismas columnas, así que es fácil de extraer la información.

Entre medias hay líneas en blanco y líneas de totales, que son fáciles de identificar...
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: Interpretar archivo de texto plano

Notapor reLlene » 2012-11-29 07:53 @370

Yo encuentro que puedo imprimir las líneas de información (como tu le llamas: el cuerpo) MIENTRAS me encuentre entre dos "tags". Me explico: tengo en cuenta a la regexp "cuotas aceptadas" como mi tag de inicio y su tag de fin a la regexp "cuotas rechazadas", luego aplico el mismo procedimiento para analizar las próximas "tags" de inicio/fin (de cuotas rechazadas a modificadas y finalmente de modificadas a la regexp "fin de listado"). Ahora entre estos tags pretendo barrer la información mediante expresiones regulares, me explico... para capturar el periodo por ejemplo con una regexp cómo: [0-9]{2}\/[0-9]{2}\s

El problema con el que me encuentro es que no sé cómo hace un while ya que siempre que abro el archivo a analizar, ¡¡¡barro línea POR línea y NO así TODO un bloque (entre tag y tag)!!! :?

Les muestro con lo que me valgo de momento.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. my $fileIn = 'reporte.txt';
  4. open( REPORTE, "<$fileIn" ) or die "[x] No se puede abrir archivo $fileIn: $!\n";
  5.  
  6. # leemos el archivo reporte a parsear
  7. my @lineas = <REPORTE>;
  8. close(REPORTE);
  9.  
  10. # quitamos el salto de linea final
  11. # chomp @lineas;
  12.  
  13. my $fileOut = 'resultado.txt';
  14. open( RESUMEN, ">$fileOut" );
  15.  
  16. $aceptadas = 'CUOTAS ACEPTADAS';
  17.  
  18. # $rechazadas='CUOTAS RECHAZADAS';
  19. # $modificadas='CUOTAS MODIFICADAS';
  20.  
  21. $periodo = '[0-9]{2}\/[0-9]{2}\s';
  22.  
  23. #$nroDeCuenta='[0-9]+{4}\s+[0-9]+{6}\s+[0-9]+{5}';
  24.  
  25. foreach $linea (@lineas) {
  26.     if ( $linea =~ m/$aceptadas/ ) { print "Aceptadas -> \n"; }
  27.     if ( $linea =~ m/$periodo/ )   { print "aca hay periodo\n"; }
  28.  
  29.     #           unless($linea =~ m/'CUOTAS RECHAZADAS'/)
  30.     #                           { print "aceptadas}
  31.     close(REPORTE);
  32.  
  33.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


consiguiendo una salida como el siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
root@sasr:~/reLlene # perl reporte.pl
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
aca hay periodo
Aceptadas ->
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
aca hay periodo
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

pero, repito... lo está haciendo línea por línea :(

Otra posibilidad que se me ocurre es asignar el archivo a una variable y a partir de allí separar por bloques (tag inicio/fin), algo como lo siguiente

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.   #!/usr/bin/perl -w
  2.  
  3.   use feature 'say';
  4.  
  5.   my $fileIn='reporte.txt';
  6.     open (REPORTE, "<$fileIn") or die "[x] No se puede abrir archivo $fileIn: $!\n";
  7.  
  8.  my $report = join  '', <REPORTE>;
  9.  close(REPORTE);
  10.  
  11.  # TENGO EL LOG EN UNA VARIABLE
  12.  # NECESITO SEPARARLA ENTRE BLOQUES
  13.  # INICIO -> CUOTAS ACEPTADAS
  14.  # FIN -> CUOTAS RECHAZADAS
  15.  
  16.  # mientras exista una regexp que encaje con un patrón como el siguiente
  17.    while ($report =~ /([0-9]{2}\/[0-9]{2})/g){
  18.     say $1;
  19.  }
  20.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

pero sigo dando vueltas, estoy muy lejos de la solucion y no le encuentro la vuelta...
¡¡Cualquier ayudita es bienvenida!! Gracias, chicos. :roll:
Última edición por explorer el 2012-11-30 09:21 @431, editado 2 veces en total
Razón: Formateado de código con Perltidy
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Interpretar archivo de texto plano

Notapor explorer » 2012-11-29 22:27 @977

Lo que puedes hacer es, al ir leyendo línea por línea, tener una variable que guarde e indique en que sección te encuentras.

Por ejemplo, el siguiente programa lee el reporte siguiendo ese modelo, y guarda la información en una estructura, para su posterior procesamiento.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4.  
  5. my $seccion;                                         # en qué sección estamos
  6. my %secciones;                                       # almacén de toda la información
  7. my %formatos = (                                     # formatos de las columnas de cada sección
  8.     ACEPTADAS   => 'x15 A17 x4 A20 A20',
  9.     RECHAZADAS  => 'x1 A17 x3 A16 x3 A5 A19 x11 A*',
  10.     MODIFICADAS => 'x6 A15 x16 A17 x12 A*',
  11. );
  12. my %largo_cabeceros = (                              # cómo de largos son las cabeceras en cada sección
  13.     ACEPTADAS   => 4,
  14.     RECHAZADAS  => 3,
  15.     MODIFICADAS => 3,
  16. );
  17.  
  18. open my $ARCHIVO, q[<], 'reporte_ameex.txt';
  19.  
  20. while (my $linea = <$ARCHIVO>) {
  21.     chomp $linea;
  22.  
  23.     # Líneas nada interesantes. Las saltamos
  24.     next if $linea =~ /^\s*$/;
  25.     next if $linea =~ /\s+-\* /;
  26.     next if $linea =~ /(?:HOJA|FECHA|HORA)\s+\d/;
  27.     next if $linea =~ /DEBITO AUTOMATICO/;
  28.     next if $linea =~ /FIN DE LISTADO/;
  29.     next if $linea =~ /TOTAL\s+(?:CICLO|S\/E|MONTO|CUOTAS)/;
  30.     next if $linea =~ /^\d+\s*$/;
  31.  
  32.     ## Saltamos líneas de la cabecera de cada hoja
  33.     if ($linea =~ /CODIGO DE ESTABLECIMIENTO/) {
  34.         <$ARCHIVO> for 1 .. $largo_cabeceros{$seccion};
  35.         next;
  36.     }
  37.  
  38.     ## Cambio de sección
  39.     if ($linea =~ /^\S?\s+CUOTAS (\w+)/) {
  40.         $seccion = $1 if $seccion ne $1;     # cambiamos la sección, si es distinta
  41.         next;
  42.     }
  43.  
  44.     ## Aquí... la magia... desempaquetamos la línea
  45.     my @cols = unpack $formatos{$seccion}, $linea;
  46.  
  47.     ## Ajuste de las cifras y comprobación de la lectura
  48.     given ($seccion) {
  49.         when ('ACEPTADAS') {
  50.             next if @cols != 3;       # salimos si no hemos leído 3 columnas
  51.             $cols[-1] =~ tr/,/./;     # cambiamos la ',' por un '.'
  52.             $cols[-1] += 0;           # lo convertimos a un número
  53.         }
  54.         when ('RECHAZADAS') {
  55.             next if @cols != 5;
  56.             $cols[3] =~ tr/,/./;
  57.             $cols[3] += 0;
  58.         }
  59.         when ('MODIFICADAS') {
  60.             next if @cols != 3;
  61.         }
  62.     }
  63.  
  64.     ## Almacenamos los datos en la estructura
  65.     push @{ $secciones{$seccion} }, [ @cols ];
  66. }
  67.  
  68. close   $ARCHIVO;
  69.  
  70. ## Volcado de la estructura en pantalla, para verla
  71. use Data::Dumper::Simple;
  72. say Dumper %secciones;
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
La salida del programa es el siguiente (abreviado):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
%secciones = (
               'ACEPTADAS' => [
                                [
                                  '3764 022430 44001',
                                  '00001          1',
                                  '21.66'
                                ],
                                [
                                  '3764 034280 61000',
                                  '00001          1',
                                  '83.91'
                                ],
                                [
                                  '3764 037470 63009',
                                  '00001          1',
                                  '91.29'
                                ],
                                [
                                  '3764 032570 52009',
                                  '00001          1',
                                  '38.5'
                                ],
                                [
                                  '3715 940000 17603',
                                  '00001          1',
                                  '91.29'
                                ],
                              ],
               'RECHAZADAS' => [
                                 [
                                   '3766 312240 62027',
                                   '00001 0000000001',
                                   '12/12',
                                   '290.16',
                                   'PRODUCTO CON STOP DEBIT'
                                 ],
                                 [
                                   '3766 851141 93037',
                                   '00001 0000000001',
                                   '12/12',
                                   '258',
                                   'NRO. CUENTA NO AUTORIZADA (ST)'
                                 ],
                                 [
                                   '3766 882741 01007',
                                   '00001 0000000001',
                                   '12/12',
                                   '103',
                                   'NRO. CUENTA NO AUTORIZADA (LC)'
                                 ],
                               ],
               'MODIFICADAS' => [
                                  [
                                    '376418354506026',
                                    '3764 188230 61015',
                                    'ALEJANDRO'
                                  ],
                                  [
                                    '376631893572005',
                                    '3766 334780 71008',
                                    'ALEJANDRO'
                                  ],
                                  [
                                    '377790800510960',
                                    '3777 920010 10831',
                                    'CUENTA GNS TRANSFERIDA'
                                  ],
                                ]
             );
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Es un hash de array de array (3D 8)). Con esto, ya podríamos empezar a trabajar.
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: Interpretar archivo de texto plano

Notapor reLlene » 2012-12-03 13:44 @614

Gracias por tu tiempo, explorer. Aprovecho para preguntarte, ajeno a los notas que has dejado como comentarios, algunas particularidades de tu código que no comprendo qué hacen con el fin de desmembrarlo un poco y aprender también cómo consigues lo que consigues al final.

Entiendo que entonces irá trabajando línea por línea del texto, a medida que lo hace con cada una de éstas saltará aquellas que no brindan información alguna como tu lo has puesto con expresiones regulares, vale. Pero luego no entiendo qué hace esta porción de código para el tratado de las columnas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %formatos =
  2.                         (                                     # formatos de las columnas de cada sección
  3.         ACEPTADAS   => 'x15 A17 x4 A20 A20',
  4.         RECHAZADAS  => 'x1 A17 x3 A16 x3 A5 A19 x11 A*',
  5.         MODIFICADAS => 'x6 A15 x16 A17 x12 A*',
  6.                    );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Navegué para ver si me topaba con algo para entender qué hacías aquí pero es que no me entero. Me pasa igual con lo que llamas "la magia":
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. ## Aquí... la magia... desempaquetamos la línea
  2.         my @cols = unpack $formatos{$seccion}, $linea;
  3.    
  4. ## Ajuste de las cifras y comprobación de la lectura
  5.         given ($seccion)
  6.                 {
  7.              when ('ACEPTADAS')
  8.                         {
  9.            next if @cols != 3;       # salimos si no hemos leído 3 columnas
  10.            $cols[-1] =~ tr/,/./;     # cambiamos la ',' por un '.'
  11.            $cols[-1] += 0;           # lo convertimos a un número
  12.          }
  13.         when ('RECHAZADAS')
  14.                         {
  15.            next if @cols != 5;
  16.            $cols[3] =~ tr/,/./;
  17.            $cols[3] += 0;
  18.          }
  19.         when ('MODIFICADAS')
  20.                         {
  21.            next if @cols != 3;
  22.          }
  23.                 }
  24.      
  25.         ## Almacenamos los datos en la estructura
  26.         push @{ $secciones{$seccion} }, [ @cols ];
  27.  
  28. }
  29.      
  30. close   $ARCHIVO;
  31.      
  32. ## Volcado de la estructura en pantalla, para verla
  33. use Data::Dumper::Simple;
  34. say Dumper %secciones;
  35.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

Y pues la idea es lograr una salida en un nuevo archivo, con eso no tengo problema (desvío la impresión DENTRO del archivo resultante) pero si al querer lograr algo del estilo csv, separados por ";" para luego sea cómodo imputar dichos datos. Me refiero obtener una salida como el siguiente:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Cuotas Aceptadas->
12/12;376402243044001;21.66
12/12;376403428061000;83.91
12/12;376403747063009;91.29
...

Cuotas Rechazadas->
376416601021097;12/12;79.78;'NRO. CUENTA INVALIDA'
376634364201017;12/12;53.00;'PRODUCTO CON STOP DEBIT'
...


Cuotas Modificadas->
376418426501012;376408221081012;HECTOR
376631893572005;376633478071008;ALEJANDRO  
...
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Después, debajo de CADA uno de estos acotar los totales, pero ya es un agregado extra para simplemente verificar que cierren los números (en los casos aceptadas y rechazadas):
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Cuotas Aceptadas->
12/12;376402243044001;10.00
12/12;376403428061000;10.00
12/12;376403747063009;30.00

Total periodo 12/12 -> 50.00

01/13;376402243044041;10.00
01/13;376403428061040;10.00
01/13;376403747063049;10.00

Total periodo 01/13 -> 30.00

Cuotas Rechazadas->
376416601021097;12/12;20.00;'NRO. CUENTA INVALIDA'
376634364201017;12/12;25.00;'PRODUCTO CON STOP DEBIT'
 TOTAL   MONTO  :            45.00  

Cuotas Modificadas->
376418426501012;376408221081012;HECTOR
376631893572005;376633478071008;ALEJANDRO  
...
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Repito, es un agregado y de momento no es mi prioridad.

Agradezco tu aclaración, explorer, y la de cualquier otra alma caritativa, claro. :cry:
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Interpretar archivo de texto plano

Notapor explorer » 2012-12-03 15:37 @692

reLlene escribiste:no entiendo qué hace esta porción de código para el tratado de las columnas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my %formatos =
  2.                         (                                     # formatos de las columnas de cada sección
  3.         ACEPTADAS   => 'x15 A17 x4 A20 A20',
  4.         RECHAZADAS  => 'x1 A17 x3 A16 x3 A5 A19 x11 A*',
  5.         MODIFICADAS => 'x6 A15 x16 A17 x12 A*',
  6.                    );
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Navegué para ver si me topaba con algo para entender qué hacías aquí pero es que no me entero.
Ahí solo estoy definiendo un hash. Nada más. Son tres claves, y a cada una le corresponde una cadena de caracteres.

reLlene escribiste:Me pasa igual con lo que llamas "la magia":
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. ## Aquí... la magia... desempaquetamos la línea
  2.         my @cols = unpack $formatos{$seccion}, $linea;
  3.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
En $seccion tenemos el nombre de la sección (ACEPTADAS, RECHAZADAS o MODIFICADAS). La usamos como clave para encontrar en %formatos el valor de la cadena de caracteres que definimos antes. Esa cadena la vamos a usar como cadena de formato para la función unpack(). Entonces, lo que estamos haciendo realmente es "desempaquetar" la $linea según el formato indicado por la $seccion en la que estamos.

Recuerda que cada sección tiene un formato de columnas distinto. Pues es precisamente eso de lo que estamos hablando: las cadenas de caracteres describen el formato de cada tipo de línea. Y unpack() "desempaqueta" la línea según el formato de columnas, y extrae los campos que le indicamos.

Por ejemplo: para ACEPTADAS, tenemos el formato 'x15 A17 x4 A20 A20', que quiere decir:
  • salta (no nos interesa) los primeros 15 caracteres
  • extrae un campo de 17 caracteres
  • salta los siguientes 4 caracteres
  • y dos campos más de 20 caracteres
Los campos son devueltos por unpack() como una lista de valores, que son almacenados en el array @cols.

Además, a los campos de caracteres se les "recorta" los espacios en blanco que tengan al final, porque consideramos que no nos interesan.

(unpack() es muy útil ;) Más información perldoc -f unpack y perldoc -f pack)

El given/when que sigue es igual al switch/case de otros lenguajes informáticos. Perl tiene este control de flujo desde Perl v5.10.

reLlene escribiste:Y pues la idea es lograr una salida en un nuevo archivo, con eso no tengo problema (desvío la impresión DENTRO del archivo resultante) pero si al querer lograr algo del estilo CSV, separados por ";" para luego sea cómodo imputar dichos datos. Me refiero obtener una salida como el siguiente:
Pues eso ya es cuestión de recorrer la estructura %secciones, pero...

En los ejemplos que pones, como salida, escribes campos que no hemos capturado, como por ejemplo, el de la fecha, en las cuotas aceptadas. No las he capturado porque no sabíamos que era importante.

De las cuotas rechazadas y modificadas, no hay muchos cambios (quitar espacios en blanco, por ejemplo), pero eso se resuelve con una sola expresión regular.

reLlene escribiste:Después, debajo de CADA uno de estos acotar los totales, pero ya es un agregado extra para simplemente verificar que cierren los números (en los casos aceptadas y rechazadas):
Pues habría que ir haciendo una suma por cada periodo (supongo que cambio de fecha), y cuando se detecta un cambio de fecha o fin de sección, imprimir el total.
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: Interpretar archivo de texto plano

Notapor reLlene » 2012-12-04 15:14 @676

Wow, explorer, muchas gracias nuevamente, impecable tu explicación, sin ella no la habría entendido.

Comento que estuve mirando en la documentación de Perl y también la brillante de Perlmonks para entender mejor el trabajo que hace la función pack y unpack, la que tenemos en nuestros tutoriales es DEMASIADO acotada ¡ja,ja! pero ahora entiendo también por qué xD

Venga, estuve siguiendo tus consejos y conseguí lo siguiente.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -w
  2.  
  3. use strict;
  4.  
  5. my $fileIn = 'reporte.txt';
  6. open( REPORTE, "<$fileIn" )
  7.     or die "[ERROR]-> No se puede abrir el archivo reporte $fileIn para ser interpretado: $!\n";
  8. my $periodo = "";
  9. my $seccion = "";                      # la definimos previamente
  10. my %formatos =                         # formatos de las columnas de cada sección
  11.     (
  12.     ACEPTADAS   => 'x15 A17 x27 A10',               # cuenta con 7 col pero sólo nos importan 3 de éstas
  13.     RECHAZADAS  => 'x1 A17 x19 x3 A5 x9 A10 A*',    # cuenta con 5 col pero no nos importa la col 'Producto'
  14.     MODIFICADAS => 'x6 A15 x16 A17 x12 A*',         # cuenta con 3 col y nos importan todas
  15.     );
  16.  
  17. while ( my $linea = <REPORTE> )        # a medida que voy leyendo la línea...
  18. {
  19.     chomp $linea;                      # quitamos la nueva línea
  20.  
  21.     # Líneas NADA interesantes. Las saltamos
  22.     next if $linea =~ /^\s*$/;         # líneas en blanco, es decir, tantos espacios cómo existan
  23.     next
  24.         if $linea
  25.             =~ /\s*-\* /;              # que contengan los caracteres '-*' (sin comillas) precedidos por espacios tantos como existan
  26.     next if $linea =~ /(?:HOJA|FECHA|HORA)\s+\d/;  # lineas dónde que contengan la expresión 'HOJA','FECHA'ú 'HORA'...
  27.     next if $linea =~ /DEBITO AUTOMATICO/;         # que contengan la expresión 'DEBITO AUTOMATICO'
  28.     next if $linea =~ /FIN DE LISTADO/;            # que contengan la expresión 'FIN DE LISTADO'
  29.     next
  30.         if $linea =~ /TOTAL\s+(?:CICLO|S\/E|MONTO|CUOTAS)/; # dónde 'TOTAL' pueda ser 'CICLO','S/E','MONTO' ó 'CUOTAS'
  31.     next if $linea =~ /^\d+\s*$/;      # líneas que comiencen con dígito simplemente (porque termina con espacios la línea)
  32.     next if $linea =~ /^\s-+/;         # para el caso ' -------- ' (última línea del encabezado, TODOS la tienen)
  33.  
  34.     if ( $linea
  35.         =~ /CODIGO DE ESTABLECIMIENTO/ )    # omitimos las próximas 4 líneas después de toparnos con ésta expresión
  36.     {
  37.         <REPORTE> for 1 .. 3;
  38.         next;
  39.     }
  40.  
  41.     # Cambio de sección
  42.     if ( $linea =~ /^\S?\s+CUOTAS (\w+)/ )    # la var $1 adopta la expresión que se encuentra entre los paréntesis
  43.     {
  44.         if ( $seccion ne $1 )          # fin de sección
  45.         {
  46.             $seccion = $1;             # si leemos una distinta, cambiamos de sección
  47.             print "SECCION:$seccion\n";       # imprimo sección, por CADA vez que nos topamos con una nueva
  48.  
  49.         }
  50.         next;
  51.     }
  52.     if ( $linea =~ /\d{1}\s{4}([0-9]{2}\/[0-9]{2})/ ) {
  53.         if ( $periodo ne $1 ) { $periodo = $1; }
  54.     }
  55.  
  56.     # desempaquetamos la línea
  57.     my @coleccion = unpack $formatos{$seccion},
  58.         $linea;                        # la cadena adoptará el formato que le corresponda según sección
  59.     unshift( @coleccion, $periodo )
  60.         if $seccion eq 'ACEPTADAS';    # agrego fecha delante de cada colección de las aceptadas
  61.     foreach my $columna (@coleccion) {
  62.         $columna =~ s/\s//g;           # eliminamos los espacios en blanco con esta regexp
  63.     }
  64.     print join( ';', @coleccion );     # obtenemos la impresión de las columnas separadas por ';'
  65.     print "\n";
  66. }
  67. close(REPORTE);
  68.  
  69.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Consiguiendo la siguiente salida en la terminal
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
SECCION:ACEPTADAS
12/12;376402243044001;21,66
12/12;376403428061000;83,91
12/12;376403747063009;91,29
12/12;376403257052009;38,50
12/12;371594000017603;91,29
12/12;371594000133004;145,08
12/12;376404902126009;29,90
12/12;376415834106009;91,29
12/12;376415114123003;59,80
12/12;377795000170273;26,50
12/12;377795000982008;138,35
12/12;377795004392302;53,00
12/12;377795005960891;5,00
12/12;377805000034456;39,89
12/12;377805800010748;11,98
12/12;377806000011756;103,00
12/12;377806800014331;21,66
12/12;376402759291006;83,91
12/12;376403444272021;103,00
12/12;376403496248051;50,70
12/12;376404040223007;145,08
12/12;376406153202020;39,89
12/12;376406744262004;103,00
12/12;376405787203006;103,00
12/12;376416581301009;31,50
12/12;376456637383004;101,00
12/12;376456177303007;334,44
12/12;376456426302008;26,50
12/12;376456689351007;96,29
12/12;376456380302008;224,98
12/12;376456551341009;157,19
12/12;376456792332007;31,50
12/12;376636669351008;101,00
12/12;376687126351008;33,14
12/12;376404455482008;145,08
12/12;376404985429008;44,89
12/12;376404006461004;91,29
12/12;376714902421007;39,89
12/12;376714130401009;98,55
12/12;372654831571004;5,00
12/12;376404069567004;90,63
12/12;376404311553000;132,90
12/12;376404744503006;39,89
12/12;376404812521006;148,99
12/12;376405232521038;29,90
12/12;376405768515008;83,79
12/12;376685515551002;116,93
12/12;376685872501004;39,89
12/12;376405001655008;5,00
12/12;376405944603009;29,90
12/12;376415597609002;91,29
12/12;376415582603000;26,50
12/12;376415191622000;103,00
12/12;376415360602007;143,35
12/12;376414284701000;122,30
12/12;376454114711004;116,93
12/12;376454526712004;91,29
12/12;376454680703008;101,00
12/12;376405112821000;108,78
12/12;376405832831016;31,50
12/12;376415167803004;103,00
12/12;376685062831013;26,50
12/12;376685989831005;26,50
12/12;376405085961009;39,89
12/12;376405084938022;5,99
12/12;376406502903021;101,00
12/12;376416814911008;15,00
12/12;376416303921003;117,30
12/12;376685435902004;39,89
12/12;376713040901007;26,50
SECCION:RECHAZADAS
376416601021097;12/12;79,78;NRO.CUENTAINVALIDA
376631224062027;12/12;290,16;PRODUCTOCONSTOPDEBIT
376685114193037;12/12;258,00;NRO.CUENTANOAUTORIZADA(ST)
376688274101007;12/12;103,00;NRO.CUENTANOAUTORIZADA(LC)
376634364201017;12/12;53,00;PRODUCTOCONSTOPDEBIT
376635884261007;12/12;182,58;PRODUCTOCONSTOPDEBIT
377790004262737;12/12;53,00;NRO.CUENTAINVALIDA
376410944422027;12/12;79,78;PRODUCTOCONSTOPDEBIT
377791004823697;12/12;77,00;NRO.CUENTAINVALIDA
SECCION:MODIFICADAS
376418426501012;376408221081012;HECTOR
376418354506026;376418823061015;ALEJANDRO
376631893572005;376633478071008;ALEJANDRO
377790800510960;377792001010831;CUENTAGNSTRANSFERIDA
377791001575149;377792001133393;CUENTAGNSTRANSFERIDA
376403595261009;376413986214006;ANA
376418675211001;376417873211009;RICARDO
376415525201005;376418207233008;VICTOR
376411495901006;376418335832002;VICTOR
376633510913000;376686435902004;RICARDO
376418547921005;376712040901007;HUGO
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Y cómo veras los encabezados son ligeramente parecidos exceptuando porque las últimas secciones (rechazadas y modificadas), por eso en lugar de saltarme las 4 líneas (renglones) que tú te salteaste sólo me salto 3 y agrego una última regexp con el fin de evitarla (porque es la última línea de los encabezados).

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.         next if $linea =~ /^\s-+/;     # para el caso ' -------- ' (última linea del encabezado, TODOS la tienen)
  2.  
  3.         if ( $linea
  4.             =~ /CODIGO DE ESTABLECIMIENTO/ ) # omitimos las próximas 4 líneas después de toparnos con ésta expresión
  5.         {
  6.             <REPORTE_AMEX> for 1 .. 3;
  7.             next;
  8.         }
  9.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Quizás no sea lo MÁS óptimo pero funciona ¡ja,ja!

Al igual que con los formatos de las secciones, los edité porque no había mencionado de aquellos datos que no me incumbían y para el tratado de las fechas (los períodos) haciendo uso del if como el trabajo que realizaste con las secciones.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     if ( $linea =~ /\d{1}\s{4}([0-9]{2}\/[0-9]{2})/ ) {
  2.         if ( $periodo ne $1 ) { $periodo = $1; }
  3.     }
  4.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Sin antes, claro, de salir del bucle e insertar dicha variable a cada una de las líneas de información (con unshift)

Ahora por último, lo que hago también es quitar los espacios en blancos como bien me has dicho haciendo uso de la siguiente regexp
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. foreach my $columna (@coleccion) {
  2.     $columna =~ s/\s//g;               # eliminamos los espacios en blanco con esta regexp
  3. }
  4.  
  5.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

y me encuentro ante el problema que NO quiero que lo haga con TODOS (foreach) los campos de la @coleccion, o mejor dicho, sí con todos EXCEPTO por el último de los campos de las ÚLTIMAS secciones (rechazadas/modificadas), pues ya no se tratan de montos sino de observaciones (llamémosle así, ¡ja,ja!) y necesito que se muestren como literales de cadena, pero claro, también debería de quitar la regla para éstos casos de quitar los espacios blancos. :?

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
...
12/12;376713040901007;26,50
SECCION:RECHAZADAS
376416601021097;12/12;79,78;'NRO.CUENTA INVALIDA'
376631224062027;12/12;290,16;'PRODUCTO CON STOP DEBIT'
376685114193037;12/12;258,00;'NRO. CUENTA NO AUTORIZADA(ST)'
376688274101007;12/12;103,00;'NRO. CUENTA NO AUTORIZADA(LC)'
376634364201017;12/12;53,00;'PRODUCTO CON STOP DEBIT'
376635884261007;12/12;182,58;'PRODUCTO CON STOP DEBIT'
377790004262737;12/12;53,00;'NRO. CUENTA INVALIDA'
376410944422027;12/12;79,78;'PRODUCTO CON STOP DEBIT'
377791004823697;12/12;77,00;'NRO.CUENTA INVALIDA'
SECCION:MODIFICADAS
376418426501012;376408221081012;'HECTOR'
376418354506026;376418823061015;'ALEJANDRO'
376631893572005;376633478071008;'ALEJANDRO'
377790800510960;377792001010831;'CUENTAGNSTRANSFERIDA'
377791001575149;377792001133393;'CUENTAGNSTRANSFERIDA'
376403595261009;376413986214006;'ANA'
...
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Preguntar por último qué puede pasar si no hago lo siguiente (sumarle 0 al monto)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.            $cols[-1] += 0;           # lo convertimos a un número
  2.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

y luego en éste otro caso cuento con montos cómo el 12.045,45
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.            $cols[-1] =~ tr/,/./;     # cambiamos la ',' por un '.'
  2.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

con lo que me quedaría con un 12.045.45 que es distinto. ¿Qué suele hacerse en estos casos donde los separo por ";", los dejo de la forma 12.045,45 o bien 12.045.45? :shock:
Última edición por explorer el 2012-12-04 18:46 @824, editado 1 vez en total
Razón: Correcciones ortográficas. linea => línea
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Re: Interpretar archivo de texto plano

Notapor explorer » 2012-12-04 19:24 @850

reLlene escribiste:Y cómo veras los encabezados son ligeramente parecidos exceptuando porque las últimas secciones (rechazadas y modificadas), por eso en lugar de saltarme las 4 líneas (renglones) que tú te salteaste sólo me salto 3 y agrego una última regexp con el fin de evitarla (porque es la última línea de los encabezados).
Pues mira, no me di cuenta de que los encabezados eran distintos, para esas secciones.

Yo lo pondría así: si sé que estoy en la línea de "CODIGO DE ESTABLECIMIENTO", según en la sección donde esté, inicializaría una variable a 3 o 4, y esas serían las líneas a saltar. De esa manera tengo todo el código de salto en un solo sitio, y no una línea next if... suelta.

También se puede resolver cómodamente con hashes, y así he reedito mi mensaje y lo he puesto.

reLlene escribiste:Ahora por último, lo que hago también es quitar los espacios en blancos como bien me has dicho haciendo uso de la siguiente regexp y me encuentro ante el problema que NO quiero que lo haga con TODOS (foreach) los campos de la @coleccion, o mejor dicho, sí con todos EXCEPTO por el último de los campos de las ÚLTIMAS secciones (rechazadas/modificadas)
Bueno, pues no se hace para el último...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.     for my $columna (@coleccion[0 .. $#coleccion-1]) {
  2.         $columna =~ s/\s//g;           # eliminamos los espacios en blanco con esta regexp
  3.     }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


reLlene escribiste:Preguntar por último qué puede pasar si no hago lo siguiente (sumarle 0 al monto)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.            $cols[-1] += 0;           # lo convertimos a un número
  2.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
Esa operación, realmente, lo que hace es quitar los espacios en blanco, que puedan sobrar, de la columna de la cantidad. Recuerda que se hace después de haber convertido la coma decimal en punto (Perl, por defecto, necesita nomenclatura anglosajona en los números).

reLlene escribiste:y luego en éste otro caso cuento con montos cómo el 12.045,45
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.            $cols[-1] =~ tr/,/./;     # cambiamos la ',' por un '.'
  2.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

con lo que me quedaría con un 12.045.45 que es distinto. ¿Qué suele hacerse en estos casos donde los separo por ";", los dejo de la forma 12.045,45 o bien 12.045.45? :shock:
Se hace dos pasos: primero quita los puntos, y luego convierte las comas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.             $cols[-1] =~ s/[.]//g;    # quitamos los '.' de adorno
  2.             $cols[-1] =~ tr/,/./;     # cambiamos la ',' por un '.'
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Por último, un detalle curioso: en Español, desde que se aprobó la última ortografía en diciembre de 2010, en los números decimales, la parte entera se separa de la decimal con punto o con coma, aunque la recomendación es usar punto, para que sea igual a la anglosajona (y facilitar la vida de los programadores). Y los separadores de millares, en lugar de un punto, hay que usar un "breve espacio en blanco" (esto es más complicado de conseguir. En la web, por ejemplo, se hace con &thinsp;).
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: Interpretar archivo de texto plano

Notapor reLlene » 2012-12-06 10:52 @494

¡Genial, explorer! Interesante la información que me haces llegar. Lo he conseguido y ahora obtengo una salida como la siguiente. :D

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
SECCION:ACEPTADAS
12/12;376687100931007;174.57
12/12;376687174903015;304.98
12/12;376687435902004;39.89
12/12;376717040901007;26.5
SECCION:RECHAZADAS
12/12;376415266111006;276.7;NRO. CUENTA NO AUTORIZADA (ST)
12/12;376415901021098;79.78;NRO. CUENTA INVALIDA
12/12;376455595011001;59.8;NRO. CUENTA NO AUTORIZADA (ST)
12/12;376638735061003;53;NRO. CUENTA NO AUTORIZADA (ST)
12/12;376638229062029;290.16;PRODUCTO CON STOP DEBIT
SECCION:MODIFICADAS
376418426008012;376408221081012;HECTOR ADRIAN
376408657428005;376418304061005;MONICA STEFANP
376410927028003;376418615041001;EDUARDO JOSE RIVA
376418354908026;376418823061015;ALEJANDRO M GHIANI
376631893178005;376633478071008;ALEJANDRO BELNI
376633316938009;376633626071009;GUSTAVO BENI
376635592728004;376686177011006;JORGE COS
376687871008012;376686198091011;SERGIO FAIO
376630971028027;376711862021027;RICARDO DURANO
377796001558130;371593000017603;CUENTA GNS TRANSFERIDA
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Si puedes ver he invertido la impresión de dos columnas en las rechazadas para que quede como la de las aceptadas (columna 2 por la 1) y lo he hecho de la siguiente manera:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ( $seccion eq 'RECHAZADAS' )
  2. {                                      # invierto orden de la 1ª y 2ª columna para que se vea similar a las líneas de la sección ACEPTADAS
  3.     print CONCLUSION $coleccion[1] . ';' . $coleccion[0] . ';' . $coleccion[2] . ';' . $coleccion[3];
  4.     print CONCLUSION "\n";
  5. }
  6. else {
  7.     print CONCLUSION join( ';', @coleccion );    # obtenemos la impresión de las columnas separadas por ';'
  8.     print CONCLUSION "\n";
  9. }
  10.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¿Un poco fea? Intuyo que debe existir alguna más bonita :lol:

Y luego, ¿es correcta la definición que hago sobre ciertas variables al comienzo del script? Me explico...

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. my $periodo="";
  2. my $seccion="";
  3.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Probé con defined($var); pero es que no sé por qué pero no resultó.

Y una duda que olvidé preguntarte, explorer, es en la siguiente porción de código:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ($linea =~ /CODIGO DE ESTABLECIMIENTO/ ) # omitimos las próximas 4 líneas después de toparnos con ésta expresión
  2. {
  3.     <REPORTE> for 1 .. 3;
  4.     next;
  5. }
  6.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Entiendo qué hace, pero ¿vendría hacer como un ciclo for con su sintaxis un poco compuesta? ¿Cierto :?:

¡¡¡Gracias compañero!!!
Sexo : unzip ; strip ; touch ; grep ; finger ;mount ; fsck ; more ; yes ; umount ; sleep.
Avatar de Usuario
reLlene
Perlero nuevo
Perlero nuevo
 
Mensajes: 97
Registrado: 2012-06-04 07:16 @344

Siguiente

Volver a Básico

¿Quién está conectado?

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