• Publicidad

Interpretar fichero CSV

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

Interpretar fichero CSV

Notapor fgalves » 2006-11-16 08:17 @387

Hola a todos,

Tengo que implementar un script Perl que haga lo siguiente:
  • Leer fichero del tipo CSV (campos separados por el carácter ';' )
  • Dicho fichero tiene una primera línea y última línea que debo ignorar, o mejor dicho, copiar literalmente en el fichero de salida.
  • A partir de la segunda línea del fichero, encontramos los campos separados por ';'.
  • El primer campo de la línea lo llamare CARF y su valor puede aparecer repetido en diferentes líneas. El segundo campo es una especie de TimeStamp o medida de tiempo.
    El objetivo de mi script, es el de suprimir las líneas repetidas y quedarme con sólo una línea por CARF, concretamente aquella con el campo TimeStamp más grande.
  • A continuación de los 2 campos antes mencionados, tengo 26 campos más, pero que no intervienen en el algoritmo y que deseo guardar tal cual.

De momento tengo la siguiente función pero que no me funciona del todo bien:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
# Process file removing repeated lines
sub processFile() {
       
    open(INFILE,"<$file_o") or die "Problem encountered opening input file\n";
    open(OUTFILE,">$file_o.mod") or die "Problem encountered generating output file\n";
   
    while (my $I=<INFILE>)
    {
        if ($lineCounter == 0){
            print OUTFILE $I;
            $lineCounter++;
        }
       
        else {
           
            ($carf, $starttime) = ($I =~ /^(\s+);(\d+);/);
           
            if ((! defined $carfStartTimes{$carf}) && (! defined $carfLines{$carf}))
            {
                $carfLines{$carf}= $I;
                $carfStartTimes{$carf}= $starttime;
            }
            if ($starttime >= $carfStartTimes{$carf})
            {
                $carfLines{$carf} = $I;
                $carfStartTimes{$carf} = $starttime;
            }

            $lineCounter++;
        }
    }
   
   
    foreach my $line (%carfLines) {
        print OUTFILE $line;
    }
   
   
    close(INFILE);
    close(OUTFILE);
}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4



Concretamente, se queja cuando hago
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if ((! defined $carfStartTimes{$carf}) && (! defined $carfLines{$carf}))
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


El resultado de la ejecución:
Código: Seleccionar todo
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 83, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 83, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 85, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 86, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 88, <INFILE> line 2.
Use of uninitialized value in numeric ge (>=) at RemoveRepeatedCARF.pl line 88, <INFILE> line 2.
Use of uninitialized value in numeric ge (>=) at RemoveRepeatedCARF.pl line 88, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 90, <INFILE> line 2.
Use of uninitialized value in hash element at RemoveRepeatedCARF.pl line 91, <INFILE> line 2.
...


¿Alguien sabe cómo solucionar mi problema?
¿Cómo tomar en cuenta lo de la última línea (la que no debo tratar)?
¿Cómo inicializar un hash y cómo saber si un key existe ya, pues es eso lo que me falla?
Muchas gracias por adelantado,
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621

Publicidad

Notapor fgalves » 2006-11-16 11:30 @521

Aparte de las dudas anteriores, me ha surgido una nueva, pues el regexp parece no funcionar. He anadido unos print para ver si recuperaba correctamente los valores de $carf y $starttime de cada linea, y parece que no funciona:


Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
# Process file removing repeated lines
sub processFile() {
       
    open(INFILE,"<$file_o") or die "Problem encountered opening input file\n";
    open(OUTFILE,">$file_o.mod") or die "Problem encountered generating output file\n";
   
    while (my $I=<INFILE>)
    {
        if ($lineCounter == 0){
            print OUTFILE $I;
            $lineCounter++;
        }
       
        else {
            ($carf, $starttime) = ($I =~ /^(\S+);(\d+);/);
            print STDOUT "CARF: $carf"."\n";
            print STDOUT "STARTTIME: $starttime"."\n";
            if ((! defined $carfStartTimes{$carf}) && (! defined $carfLines{$carf}))
            {
                $carfLines{$carf}= $I;
                $carfStartTimes{$carf}= $starttime;
            }
            if ($starttime >= $carfStartTimes{$carf})
            {
                $carfLines{$carf} = $I;
                $carfStartTimes{$carf} = $starttime;
            }

            $lineCounter++;
        }
    }
   
   
    foreach my $line (%carfLines) {
        print OUTFILE $line;
    }
   
   
    close(INFILE);
    close(OUTFILE);
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4




El resultado:

Código: Seleccionar todo
Use of uninitialized value in concatenation (.) or string at RemoveRepeatedCARF.pl line 82, <INFILE> line 2.
CARF:
Use of uninitialized value in concatenation (.) or string at RemoveRepeatedCARF.pl line 83, <INFILE> line 2.
STARTTIME:


Por informacion, CARF es una tira de numeros o letras separados por multiples '_'
Ej: 12314_2323_fweFFE_342342

StartTime es un valor numerico (un conjunto de digitos).

Gracias por adelantado,
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621

Notapor explorer » 2006-11-16 11:56 @539

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -w

$file_o = 'A.csv';

open(INFILE, "<$file_o")     or die "Problem encountered opening input file $file_o\n";
open(OUTFILE,">$file_o.mod") or die "Problem encountered generating output file $file_o.mod\n";

# Primera línea
$I = <INFILE>; print OUTFILE $I;

# Siguientes líneas
while ( $I = <INFILE> ) {

    # Si es una línea con datos...
    if ( ($carf, $starttime, $resto) = $I =~ /^(.+?);(\d+);(.+)/ ) {

        # Lo guardamos
        #   si no está definido o si es superior en tiempo
        $carfLines{ $carf } = [ $starttime, $resto ]
            if not defined $carfLines{ $carf } or $starttime > $carfLines{ $carf }->[0];

    }
    else {
        # Última línea (lo suponemos)
        $ultima = $I;
    }
}
close INFILE;

# Sacamos el nuevo fichero ordenado por el primer campo
foreach $carf ( sort keys %carfLines )  {
    print OUTFILE "$carf;$carfLines{$carf}->[1]\n";
}
print OUTFILE $ultima;
close OUTFILE;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
La expresión regular está un poco cambiada, ya que la tuya no funcionaba.

En este ejemplo, suponemos que la última línea no coincide con la expresión regular, por la que guardamos en un variable para sacarla después.

Además, vamos guardando las líneas leídas en un hash. Cada elemento del hash es un array. Y dentro del array, el primer elemento es el tiempo y segundo elemento es la línea entera.

A la hora de sacarlo, lo hacemos de forma ordenada (ordenando por las claves leídas alfabéticamente).
Última edición por explorer el 2006-11-16 13:44 @614, editado 3 veces en 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

Notapor fgalves » 2006-11-16 12:32 @564

Muchísimas gracias explorer. Lo he probado y va perfecto.
Tu solución es mucho más eficiente que la que yo estaba intentando implementar.
El problema de la ultima línea, lo pretendía corregir llamando a una función que al principio abría el fichero e incrementaba un contador para saber el número de líneas totales.
El problema del regexp, lo había solucionado sustituyendo (/S+) por ([/w/s]+), ya que CARF puede contener espacios en blanco al principio.

Por último, aprovecho para preguntarte algo: en el fichero de salida, el output, hay algún modo rápido de eliminar el segundo campo (StartTime)? Es decir, obtener el mismo CSV de salida pero sin la segunda columna correspondiente al valor numérico del tiempo, que me ha servido únicamente para escoger la línea correcta .

Muchísimas gracias de todos modos,
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621

Notapor explorer » 2006-11-16 13:02 @585

Ya está cambiado para eliminar el campo del tiempo.

No sé si será más eficiente o es más corta. Lo importante es que funcione y que lo entiendas.

Para lo de la última fila hay otra solución: leer todo el fichero con @lineas = <INFILE>; y una vez que está todo en el array, es fácil acceder al primer elemento ([0]) y al último ([-1]).

En la expresión regular, si se trata de un CSV, lo importante son los separadores, y por eso lo usé en la mía.
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

Notapor fgalves » 2006-11-17 02:39 @152

Gracias de nuevo explorer,

No dudes ni un segundo de que hago todo el esfuerzo posible por entender vuestras aportaciones, y por absorber como una esponja vuestras enseñanzas. Soy novato en Perl, y todavía lo veo como un lenguaje con construcciones raras, demasiado permisivo desde mi punto de vista. Fui contratado por una empresa francesa para implementar en C (el cual conozco bastante mejor y aunque dota de gran libertad al programador, lo veo un lenguaje más cerrado y lisible), y al final me metieron en un proyecto implementado en Perl...

Es evidente que la practica hace al maestro, pero lo que para gente como tu (expertos o gurus) puede parecer algo trivial y que se puede hacer en 5 minutos, a mí (aun teniendo el pseudo-algoritmo en la cabeza) me puede traer varios dolores de cabeza y tardar horas en hacer, como el caso que nos ocupa.

Solo el aprendizaje de las regexp ya da para escribir un libro entero (y soy bien consciente de que los hay a tutiplen).

Todo eso para desde aquí felicitar vuestra magnifica labor (en especial a ti, que normalmente eres el que me ayudas), y que sigáis en ese ritmo, y con la misma paciencia con los novatos como yo. Al final todos saldremos ganando y quien sabe, algún día yo también podre resolver la duda de algún otro novato...

Muchísimas gracias,
Felipe
fgalves
Perlero nuevo
Perlero nuevo
 
Mensajes: 210
Registrado: 2006-09-25 13:54 @621


Volver a Básico

¿Quién está conectado?

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

cron