2012-01-21 18:19 @805 |
|
|
MARKO
Perlero Nuevo
|
Registrado: 2012-01-10 22:34 @982 Mensajes: 23
|
|
|
Optimizar transformación de archivos Excel a texto
|
El archivo que necesito transformar tiene tres hojas (vfp, corriente, datos). En vfp extraigo las variables $vnominal, $mPT, $pacep y $mpot. En corriente extraigo las variables $CT, $CENS. En datos extraigo once columnas de un mínimo de 2880 datos. La hoja de datos es la que transformo a texto y la columna de fechas las transformo a un formato conveniente. La hoja de datos está así:  Esta conversión la realizo con la ayuda del módulo SpreadSheet::ParseExcel y el archivo de texto resultado contiene dos columnas más uno de numeración y otra con la letra "i". Adjunto el código que me transforma el Excel a texto y obtiene las variables antes mencionadas. Using perl Syntax Highlighting use Spreadsheet::ParseExcel;
$nombre = "AT911201.xls";
sub CONVERSION {
$a = 0;
$b = 0;
$c = 0;
my $parser = Spreadsheet::ParseExcel->new();
my $libro = $parser->parse($nombre);
if ( !defined $libro ) {
die $parser->error(), ".\n";
}
my $hojanombre;
my $hoja;
my $indice;
my $hojas = $libro->worksheets();
for $indice ( $libro->worksheets() ) {
$hojanombre = $indice->get_name();
$hojanombre = lc($hojanombre);
if ( $hojanombre eq "vfp" ) {
$hoja = $indice;
$a = 1;
last;
}
}
if ( $a == 1 ) {
$vnominal = $hoja->get_cell( 1, 3 )->value(); #VARIABLES
$mPT = $hoja->get_cell( 2, 3 )->value();
$pacep = $hoja->get_cell( 3, 3 )->value();
$mpot = $hoja->get_cell( 4, 3 )->value();
}
for $indice ( $libro->worksheets() ) {
$hojanombre = $indice->get_name();
$hojanombre = lc($hojanombre);
if ( $hojanombre eq "corriente" ) {
$hoja = $indice;
$b = 1;
last;
}
}
if ( $b == 1 ) {
$CT = $hoja->get_cell( 2, 6 )->value(); #VARIABLES
$CENS = $hoja->get_cell( 3, 6 )->value();
}
for $indice ( $libro->worksheets() ) {
$hojanombre = $indice->get_name();
$hojanombre = lc($hojanombre);
if ( $hojanombre eq "datos" ) {
$hoja = $indice;
$c = 1;
last;
}
}
if ( $c == 1 ) {
my ( $minfila, $maxfila ) = $hoja->row_range;
my ( $mincol, $maxcol ) = $hoja->col_range;
my @linea = ();
my $string;
$contador = 0;
for my $fila ( $minfila .. $maxfila ) {
@linea = ();
for my $columna ( $mincol .. $maxcol ) {
my $celda = $hoja->get_cell( $fila, $columna );
if ( defined($celda) ) {
#
my $variable = $celda->value();
if ( $columna == 0 and $fila > 0 ) { #CONVERTIMOS EL FORMATO DE FECHA
my @cantidades = split( "-", $variable );
if ( $cantidades[1] eq "Ene" ) {
$cantidades[1] = "01";
}
if ( $cantidades[1] eq "Feb" ) {
$cantidades[1] = "02";
}
if ( $cantidades[1] eq "Mar" ) {
$cantidades[1] = "03";
}
if ( $cantidades[1] eq "Abr" ) {
$cantidades[1] = "04";
}
if ( $cantidades[1] eq "May" ) {
$cantidades[1] = "05";
}
if ( $cantidades[1] eq "Jun" ) {
$cantidades[1] = "06";
}
if ( $cantidades[1] eq "Jul" ) {
$cantidades[1] = "07";
}
if ( $cantidades[1] eq "Ago" ) {
$cantidades[1] = "08";
}
if ( $cantidades[1] eq "Sep" ) {
$cantidades[1] = "09";
}
if ( $cantidades[1] eq "Oct" ) {
$cantidades[1] = "10";
}
if ( $cantidades[1] eq "Nov" ) {
$cantidades[1] = "11";
}
if ( $cantidades[1] eq "Dic" ) {
$cantidades[1] = "12";
}
my @cantidadess = split( " ", $cantidades[2] );
chop( $cantidadess[1] );
chop( $cantidadess[1] );
chop( $cantidadess[1] );
chop( $cantidadess[1] );
my $temporal = $cantidadess[0];
$cantidadess[0] = $cantidades[0];
$cantidades[0] = $temporal;
$cantidades[2] = join( " ", @cantidadess );
$variable = join( "/", @cantidades );
}
push( @linea, $variable );
#
}
else {
$celda = "";
push( @linea, $celda );
}
}
my $string = join( "\t", @linea ); #CONSTRUIMOS EL ARCHIVO LINEA A LINEA
$string = "$contador\t" . "i\t" . $string;
$nombre =~ s/.xls/.txt/; #CAMBIAMOS DE EXTENSIÓN .xls-->.txt
$nombre = ">>" . $nombre; #SOBREESCRIBIREMOS
open( ARCHIVO, $nombre ) or die "no se encuentra\n";
print ARCHIVO "$string\n";
close ARCHIVO;
$contador++;
}
}
}
El proceso completo se tarda 1 minuto 45 segundos, aproximadamente. Me pregunto si alguien tiene una idea para optimizar la rutina. Gracias por adelantado.
| Última edición por explorer el 2012-01-21 19:21 @848, editado 2 veces en total |
| Formateado de código con Perltidy |
|
2012-01-21 19:11 @841 |
|
|
 |
explorer
Administrador
|
Registrado: 2005-07-24 18:12 @800 Ubicación: Valladolid, España Mensajes: 10268
|
|
|
Re: Optimizar transformación de archivos Excel a texto
|
En la línea 3 declaras y defines este hash: Using perl Syntax Highlighting my %meses_a_numero = (
Ene => '01',
Feb => '02',
Mar => '03',
Abr => '04',
May => '05',
Jun => '06',
Jul => '07',
Ago => '08',
Sep => '09',
Oct => 10,
Nov => 11,
Dic => 12,
);
y luego, las líneas 71 a 117 las cambias por: Using perl Syntax Highlighting my($anno, $mes, $dia, $hora) = $variable =~ /^(\d+)-(\d+)-(\d+) ([\d:]+)/i;
if (defined $meses_a_numero{$mes}) {
$mes = $meses_a_numero{$mes};
}
$variable = "$dia/$mes/$anno $hora";
Más... no es óptimo el abrir y cerrar el fichero continuamente... - mueve las líneas 130 a 132 antes del for() de la 62
- mueve la línea 134 después de la 136
Se pueden hacer más cosas, desde luego...
_________________ JF^D Perl programming
|
2012-01-22 00:43 @072 |
|
|
MARKO
Perlero Nuevo
|
Registrado: 2012-01-10 22:34 @982 Mensajes: 23
|
|
|
Re: Optimizar transformación de archivos Excel a texto
|
Te agradezco la respuesta tan pronta, se ve que aun no soy consciente de la potencia de los hash ya que lo que pusiste esta buenísimo. Citar: Más... no es óptimo el abrir y cerrar el fichero continuamente... mueve las líneas 130 a 132 antes del for() de la 62 mueve la línea 134 después de la 136 ¡je,je! Completamente de acuerdo. De hecho en el programa original, estas líneas (130 y 132) no van allí, van en la línea 60 y 61 y de la línea 134 no me había percatado de eso. Probaré lo del hash. Te darás cuenta de mi gusto por los ciclos "for anidados" ¡je,je,je! Gracias.
|
2012-01-22 02:27 @143 |
|
|
 |
explorer
Administrador
|
Registrado: 2005-07-24 18:12 @800 Ubicación: Valladolid, España Mensajes: 10268
|
|
|
Re: Optimizar transformación de archivos Excel a texto
|
Aparte de que las banderas $a, $b y $c pueden ser omitidas (ya que bastaría con meter las líneas que afectan en el lugar donde activamos cada bandera), la necesidad de usar bucles anidados es por las limitaciones que te da el módulo Spreadsheet::ParseExcel, ya que solo te da la opción de recuperar una celda cada vez, con el método get_cell(). Yo suelo usar el módulo Spreadsheet::Read, que, aunque pueda parecer lioso al principio, puedes contar luego con funciones como row() o cellrow(), que te devuelven una línea entera cada vez, por lo que los bucles se reducen a uno. Y si, dentro de unos meses, el cliente se cansa de pagar licencias de Micro$oft Office y se pasa a LibreOffice o CSV, me basta con cambiar una línea del programa para que siga funcionando igual. Otro detalle más cosmético: dar nombres consecuentes a las variables. Eso de tener una variable llamada @cantidades y otra @cantidadess no es nada aconsejable. En cualquier momento te equivocas, y Perl no puede ayudarte aún teniendo el 'strict' y el 'warnings' activado. Incluso a la hora de editar el fichero, el autocompletado de variables se vuelve inútil y lioso. Y no te digo nada cuando vuelvas a leer este código dentro de unos meses.
_________________ JF^D Perl programming
|
2012-01-23 22:34 @982 |
|
|
MARKO
Perlero Nuevo
|
Registrado: 2012-01-10 22:34 @982 Mensajes: 23
|
|
|
Re: Optimizar transformación de archivos Excel a texto
|
Gracias explorer, te cuento que mejoró mucho el proceso con el método del hash y la expresión regular En la PC que estoy trabajando (que es viejísima y no tiene casi nada de memoria) el proceso dura 1 minuto 25 segundos. Al probar el programa en una PC con más memoria el proceso completo (transformación, verificación y creación de informe) se tardó 20 segundos  Using perl Syntax Highlighting my($anno, $mes, $dia, $hora) = $variable =~ /^(\d+)-(\d+)-(\d+) ([\d:]+)/i;
Lo único que deseo comentar es que a esta sintaxis había que cambiarle en el segundo paréntesis una cosa mínima para que funcionara: Using perl Syntax Highlighting my($anno, $mes, $dia, $hora) = $variable =~ /^(\d+)-(\D+)-(\d+) ([\d:]+)/i;
Lo último que me gustaría preguntarte es si me podrías explicar un poco más ampliamente la sintaxis de la expresión regular; ya entiendo lo de los \d y \D pero no lo de los signos - y + y los corchetes [] y los : me perdió y la opción "i" que está de último. Gracias por adelantado.
|
|
Página 1 de 1
|
[ 6 mensajes ] |
|
| Reglas del Foro |
No puedes abrir nuevos temas en este Foro No puedes responder a temas en este Foro No puedes editar tus mensajes en este Foro No puedes borrar tus mensajes en este Foro No puedes enviar adjuntos en este Foro
|
|
Socializa |
 |
|