2012-06-17 14 views
6

Sono relativamente nuovo a Perl e ho trovato questo progetto con cui mi sto divertendo un po '. L'oggetto del progetto è di confrontare due file CSV, uno dei quali conterrà: $ nome, $ modello, $ versione e l'altro che conterrà: $ nome2, $ disco, $ archiviazione alla fine il Il file RESULT conterrà le righe corrispondenti e metterà insieme le informazioni in questo modo: $ nome, $ modello, $ versione, $ disco, $ archiviazione.saltando una linea in un array, Perl

Sono riuscito a farlo, ma il mio problema è che quando uno degli elementi mancanti nel programma si interrompe. Quando incontra una linea nel file che manca un elemento si ferma su quella linea. Come posso risolvere questo problema? qualche suggerimento o un modo su come posso forse saltare quella linea e continuare?

Ecco il mio codice:

open(TESTING, '>testing.csv'); # Names will be printed to this during testing. only .net  ending names should appear 
open(MISSING, '>Missing.csv'); # Lines with missing name feilds will appear here. 

#open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); 
#my (@array) =<FILE>; 
my @hostname; #stores names 

#close FILE; 
#***** TESTING TO SEE IF ANY OF THE LISTED ITEMS BEGIN WITH A COMMA AND DO NOT HAVE A NAME. 
#***** THESE OBJECTS ARE PLACED INTO THE MISSING ARRAY AND THEN PRINTED OUT IN A SEPERATE 
#***** FILE. 
#open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); 
#test 
if (open(FILE, "file.txt")) { 

} 
else { 
    die " Cannot open file 1!\n:$!"; 

} 

$count = 0; 
$x  = 0; 
while (<FILE>) { 

    ($name, $model, $version) = split(","); #parsing 

    #print $name; 
    chomp($name, $model, $version); 

    if (($name =~ /^\s*$/) 
     && ($model =~ /^\s*$/) 
     && ($version =~ /^\s*$/)) #if all of the fields are blank (just a blank space) 
    { 

    #do nothing at all 
    } 
    elsif ($name =~ /^\s*$/) { #if name is a blank 
    $name =~ s/^\s*/missing/g; 
    print MISSING "$name,$model,$version\n"; 

    #$hostname[$count]=$name; 
    #$count++; 
    } 
    elsif ($model =~ /^\s*$/) { #if model is blank 
    $model =~ s/^\s*/missing/g; 
    print MISSING"$name,$model,$version\n"; 
    } 
    elsif ($version =~ /^\s*$/) { #if version is blank 
    $version =~ s/^\s*/missing/g; 
    print MISSING "$name,$model,$version\n"; 
    } 

    # Searches for .net to appear in field "$name" if match, it places it into hostname array. 
    if ($name =~ /.net/) { 

    $hostname[$count] = $name; 
    $count++; 
    } 

#searches for a comma in the name feild, puts that into an array and prints the line into the missing file. 
#probably won't have to use this, as I've found a better method to test all of the feilds ($name,$model,$version) 
#and put those into the missing file. Hopefully it works. 
#foreach $line (@array) 
#{ 
#if($line =~ /^\,+/) 
#{ 
#$line =~s/^\,*/missing,/g; 
#$missing[$x]=$line; 
#$x++; 
#} 
#} 

} 
close FILE; 

for my $hostname (@hostname) { 
    print TESTING $hostname . "\n"; 
} 

#for my $missing(@missing) 
#{ 
# print MISSING $missing; 
#} 
if (open(FILE2, "file2.txt")) { #Run this if the open succeeds 

    #open outfile and print starting header 
    open(RESULT, '>resultfile.csv'); 
    print RESULT ("name,Model,version,Disk, storage\n"); 
} 
else { 
    die " Cannot open file 2!\n:$!"; 
} 
$count = 0; 
while ($hostname[$count] ne "") { 
    while (<FILE>) { 
    ($name, $model, $version) = split(","); #parsing 

    #print $name,"\n"; 

    if ($name eq $hostname[$count]) # I think this is the problem area. 
    { 
     print $name, "\n", $hostname[$count], "\n"; 

     #print RESULT"$name,$model,$version,"; 
     #open (FILE2,'C:\Users\hp-laptop\Desktop\file2.txt'); 
     #test 
     if (open(FILE2, "file2.txt")) { 

     } 
     else { 
     die " Cannot open file 2!\n:$!"; 

     } 

     while (<FILE2>) { 
     chomp; 
     ($name2, $Dcount, $vname) = split(","); #parsing 

     if ($name eq $name2) { 
      chomp($version); 
      print RESULT"$name,$model,$version,$Dcount,$vname\n"; 

     } 

     } 

    } 

    $count++; 
    } 

    #open (FILE,'C:\Users\hp-laptop\Desktop\file.txt'); 
    #test 
    if (open(FILE, "file.txt")) { 

    } 
    else { 
    die " Cannot open file 1!\n:$!"; 

    } 

} 

close FILE; 
close RESULT; 
close FILE2; 
+2

Nella prossima volta si prega di utilizzare rigorosamente il codice, che ti protegge da fastidiosi bug. –

+0

Si prega di usare 'strict strict;', 'use warnings;', indietreggia il proprio codice, usa la versione dell'argomento di open con i filehandle lessicali e impara come usare le funzioni di array ('push, map, grep'). – dgw

+1

Indipendentemente dai materiali che utilizzi per insegnarti in Perl, ti consiglio caldamente di lasciarli cadere - il tuo codice è basato su modelli che vanno dal semplice obsoleto (maniglie di file con nome globale, forma a 2-arg di apertura) a decisamente sbagliato. Si prega di non prenderlo personalmente - ovviamente non è colpa tua, ma saresti MOLTO MOLTO servito imparando da libri/esercitazioni/esempi di codice molto migliori e più moderni di quello che stai chiaramente usando. – DVK

risposta

2

Penso che si desidera next, che vi permette di concludere l'iterazione corrente immediatamente e iniziare la prossima:

while (<FILE>) { 
    ($name, $model, $version) = split(","); 
    next unless($name && $model && $version); 
    ...; 
    } 

La condizione che si utilizza dipende da ciò che valori che accetterai. Nei miei esempi, presumo che tutti i valori debbano essere veri. Se hanno bisogno di non essere solo la stringa vuota, forse di controllare la lunghezza invece:

while (<FILE>) { 
    ($name, $model, $version) = split(","); 
    next unless(length($name) && length($model) && length($version)); 
    ...; 
    } 

Se sai come convalidare ogni campo, si potrebbe avere subroutine per chi:

while (<FILE>) { 
    ($name, $model, $version) = split(","); 
    next unless(length($name) && is_valid_model($model) && length($version)); 
    ...; 
    } 

sub is_valid_model { ... } 

Ora solo bisogno di decidere come integrarlo in ciò che stai già facendo.

+0

Grazie mille per il vostro contributo. Cercherò di rielaborare il mio codice con questo e postare quello che succede! – user1462038

2

È necessario iniziare aggiungendo use strict e use warnings all'inizio del programma e dichiarando tutte le variabili con my al loro primo utilizzo. Ciò rivelerà un sacco di errori semplici che sono altrimenti difficili da individuare.

Si dovrebbe anche usare i tre parametri per di open e filehandle lessicali, e il linguaggio Perl per il controllo delle eccezioni per aprire i file è quello di aggiungere or die a un open chiamata. if dichiarazioni con un blocco vuoto per lo spazio di spreco del percorso di successo e diventano illeggibili. Una open chiamata dovrebbe essere così

open my $fh, '>', 'myfile' or die "Unable to open file: $!"; 

Infine, è molto più sicuro di utilizzare un modulo Perl quando si gestisce file CSV come ci sono un sacco di insidie ​​in utilizzando un semplice split /,/. Il modulo Text::CSV ha svolto tutto il lavoro per te ed è disponibile su CPAN.

Il problema è che, dopo aver letto fino alla fine del primo file, non è necessario riavvolgerlo o riaprirlo prima di leggere nuovamente lo stesso handle nel secondo ciclo annidato. Ciò significa che non verranno letti più dati da quel file e il programma si comporterà come se fosse vuoto.

È una cattiva strategia leggere lo stesso file centinaia di volte solo per accoppiare record corrispondenti. Se il file ha dimensioni ragionevoli, è necessario creare una struttura dati in memoria per conservare le informazioni. Un hash Perl è ideale in quanto consente di cercare istantaneamente i dati corrispondenti a un determinato nome.

Ho scritto una revisione del codice che dimostra questi punti. Sarebbe imbarazzante per me testare il codice perché non ho dati di esempio, ma se continui ad avere problemi, faccelo sapere.

use strict; 
use warnings; 

use Text::CSV; 

my $csv = Text::CSV->new; 

my %data; 

# Read the name, model and version from the first file. Write any records 
# that don't have the full three fields to the "MISSING" file 
# 
open my $f1, '<', 'file.txt' or die qq(Cannot open file 1: $!); 

open my $missing, '>', 'Missing.csv' 
    or die qq(Unable to open "MISSING" file for output: $!); 
    # Lines with missing name fields will appear here. 

while (my $line = csv->getline($f1)) { 

    my $name = $line->[0]; 

    if (grep $_, @$line < 3) { 
    $csv->print($missing, $line); 
    } 
    else { 
    $data{$name} = $line if $name =~ /\.net$/i; 
    } 
} 

close $missing; 

# Put a list of .net names found into the testing file 
# 
open my $testing, '>', 'testing.csv' 
    or die qq(Unable to open "TESTING" file for output: $!); 
    # Names will be printed to this during testing. Only ".net" ending names should appear 

print $testing "$_\n" for sort keys %data; 

close $testing; 

# Read the name, disk and storage from the second file and check that the line 
# contains all three fields. Remove the name field from the start and append 
# to the data record with the matching name if it exists. 
# 
open my $f2, '<', 'file2.txt' or die qq(Cannot open file 2: $!); 

while (my $line = $csv->getline($f2)) { 

    next unless grep $_, @$line >= 3; 

    my $name = shift @$line; 
    next unless $name =~ /\.net$/i; 

    my $record = $data{$name}; 
    push @$record, @$line if $record; 
} 

# Print the completed hash. Send each record to the result output if it 
# has the required five fields 
# 
open my $result, '>', 'resultfile.csv' or die qq(Cannot open results file: $!); 

$csv->print($result, qw(name Model version Disk storage)); 

for my $name (sort keys %data) { 

    my $line = $data{$name}; 

    if (grep $_, @$line >= 5) { 
    $csv->print($result, $data{$name}); 
    } 
} 
+0

Grazie mille per questo! dall'osservare questo codice, ho una migliore comprensione di come dovrei fare questo. L'unico problema è che non sono autorizzato a utilizzare i moduli CPAN. – user1462038

+0

Se non sei autorizzato, allora questo suggerisce che si tratta di compiti a casa e non di un semplice problema che hai "incontrato". La divulgazione completa è solo educata. – mlp

+0

Mi dispiace, no. Questo non è compito a casa. Semplicemente non mi è permesso modificare i programmi sul computer che uso. Grazie comunque per la tua opinione. – user1462038

Problemi correlati