2012-06-17 15 views
6

Jestem stosunkowo nowy w Perlu i natknąłem się na ten projekt, z którym mam problem. Celem projektu jest porównanie dwóch plików CSV, z których jeden zawiera: $ nazwa, $ model, $ wersja i druga, która zawiera: $ name2, $ disk, $ storage na końcu Plik RESULT będzie zawierał dopasowane linie i zawiera informacje takie jak: $ nazwa, model $, wersja $, dysk $, magazyn $.pomijanie linii w tablicy, Perl

Udało mi się to zrobić, ale moim problemem jest to, że gdy jeden z brakujących elementów zostanie przerwany. Po napotkaniu linii w pliku brakuje elementu zatrzymuje się w tej linii. Jak mogę rozwiązać ten problem? wszelkie sugestie lub sposób, w jaki sposób mogę sprawić, że pominie tę linię i będzie kontynuował?

Oto mój kod:

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

Następnym razem użyj ścisłego kodu, chroni przed irytującymi błędami. –

+0

Proszę 'użyj ścisłego;', 'użyj ostrzeżenia;', wprowadź wcięcie w kod poprawnie, użyj wersji argumentu open z leksykalnymi uchwytami plików i naucz się korzystać z funkcji tablicowych ('push, map, grep'). – dgw

+1

Niezależnie od tego, jakich materiałów używasz do samodzielnego uczenia się w Perlu, zdecydowanie radzę je upuścić - twój kod jest oparty na szablonach, które są bardzo nieaktualne (globalnie nazwane uchwyty plików, otwarta forma 2-arg) do wręcz błędnych. Proszę nie brać tego osobiście - to oczywiście nie twoja wina, ale byłbyś bardzo BARDZO dobrze obsługiwany przez uczenie się z dużo lepszych i bardziej nowoczesnych książek/tutoriali/przykładów kodu, niż to, czego wyraźnie używasz. – DVK

Odpowiedz

2

myślę chcesz next, który pozwala natychmiast zakończyć bieżącej iteracji i rozpocząć następny:

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

warunkiem, że używasz zależy co wartości, które zaakceptujesz. W moich przykładach zakładam, że wszystkie wartości muszą być prawdziwe. Jeśli trzeba po prostu nie być pusty ciąg, może sprawdzić długość Zamiast:

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

Jeśli wiesz, jak sprawdzić poprawność każdego pola, można mieć podprogramów dla tych:

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

sub is_valid_model { ... } 

Teraz wystarczy zdecydować, jak zintegrować to z tym, co już robisz.

+0

Dziękuję bardzo za twój wkład. Spróbuję przerobić mój kod za pomocą tego i opublikować co się stanie! – user1462038

2

Powinieneś zacząć od dodania use strict i use warnings do początku programu i zadeklarowania wszystkich zmiennych za pomocą my w punkcie pierwszego użycia. To ujawni wiele prostych błędów, które w innym przypadku są trudne do wykrycia.

Należy również użyć trójparametrowy albowiem open i uchwytów plików leksykalnych i idiom Perl do sprawdzania wyjątki dotyczące otwierania plików jest dodanie or die do open rozmowy. if Wyrażenia z pustym blokiem dla przestrzeni dyskowej ścieżki sukcesu i stają się nieczytelne. open połączenie powinno wyglądać tak

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

Wreszcie, jest o wiele bezpieczniejsze w użyciu moduł Perl podczas obsługi plików CSV, jak istnieje wiele pułapek w użyciu prostego split /,/. Moduł Text::CSV wykonał całą pracę za Ciebie i jest dostępny na CPAN.

Problem polega na tym, że po przeczytaniu do końca pierwszego pliku, nie przewijaj go ponownie ani nie otwieraj ponownie przed ponownym odczytaniem z tego samego uchwytu w drugiej pętli zagnieżdżonej. Oznacza to, że z tego pliku nie będzie już żadnych danych, a program będzie zachowywał się tak, jakby był pusty.

To jest zła strategia, aby czytać setki razy ten sam plik tylko po to, aby powiązać odpowiednie zapisy. Jeśli plik ma rozsądny rozmiar, powinieneś zbudować strukturę danych w pamięci w celu przechowywania informacji. A hasl Perla jest idealny, ponieważ pozwala od razu wyszukać dane odpowiadające danej nazwie.

Napisałem rewizję kodu, który demonstruje te punkty. Byłoby niezręcznie testować kod, ponieważ nie mam przykładowych danych, ale jeśli nadal będziesz mieć problemy, daj nam znać.

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

Dziękuję bardzo za to! patrząc na ten kod, coraz lepiej rozumiem, jak powinienem to zrobić. Jedynym problemem jest to, że nie wolno mi używać modułów CPAN. – user1462038

+0

Jeśli jesteś "niedozwolony", oznacza to, że jest to praca domowa, a nie tylko problem, z którym się zetknąłeś. Pełne ujawnienie jest po prostu uprzejmy. – mlp

+0

Przepraszam, nie. To nie jest praca domowa. Po prostu nie wolno mi modyfikować programów na komputerze, którego używam. Dzięki za twój widok. – user1462038