2012-06-17 2 views
6

나는 비교적 새로운 Perl이고 나는이 프로젝트를 통해 내가 힘든 시간을 보냈다. 프로젝트의 목적은 두 개의 CSV 파일을 비교하는 것입니다. 그 중 하나는 $ name, $ model, $ version 이고 다른 하나는 $ name2, $ disk, $ storage RESULT 파일에는 일치하는 행이 포함될 것이며 $ name, $ model, $ version, $ disk, $ storage와 같은 정보를 함께 넣을 것입니다.배열의 라인을 건너 뛰기, Perl

나는이 일을 처리했지만 내 문제는 프로그램을 빠뜨린 요소 중 하나가 고장 났을 때이다. 파일에서 요소가 누락 된 행을 발견하면 해당 행에서 중지합니다. 이 문제를 어떻게 해결할 수 있습니까? 어쩌면 내가 그 라인을 건너 뛰고 계속할 수있는 방법에 대한 제안이나 방법?

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

당신은 무엇에 따라 사용 조건 : 당신은 당신이 다음을 즉시 현재 반복을 완료하고 시작할 수있는 next을 원한다고 생각

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

다음에 코드에 엄격하게 사용하십시오. 귀찮은 버그를 보호합니다. –

+0

'use strict ','use warnings;', 코드를 올바르게 들여 쓰기, 어휘 파일 핸들과 함께 open의 인수 버전을 사용하고 배열 함수 ('push, map, grep') 사용법을 배우십시오. – dgw

+1

당신이 펄을 가르치기 위해 사용하는 자료가 무엇이든지, 나는 그 형식을 삭제할 것을 강력히 권합니다 - 코드는 매우 오래된 것 (전역 이름 지정된 파일 핸들, 2-arg 형식의 열린 형식)에서 완전히 잘못된 것에 이르기까지 다양한 템플릿을 기반으로합니다. 개인적으로 받아들이지 마십시오. 분명히 잘못이 아닙니다.하지만 분명히 사용하고있는 것보다 훨씬 더 현대적이고 더 현대적인 책/학습서/코드 예제를 통해 매우 잘 배울 수 있습니다. – DVK

답변

2

: 여기

내 코드입니다 값을 받아 들일 것입니다. 나의 예에서는, 나는 모든 가치가 진실이어야한다고 가정하고있다. 그들은 단지 빈 문자열되지해야하는 경우, 어쩌면 당신이 대신 길이 확인 : 각 필드의 유효성을 검사하는 방법을 알고 있다면

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

을, 당신은 사람들을 위해 서브 루틴이있을 수 있습니다 :

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

sub is_valid_model { ... } 

지금 당신은 이미 수행중인 작업에이를 통합하는 방법을 결정할 필요가 있습니다.

+0

입력 해 주셔서 대단히 감사드립니다. 이 코드를 수정하고 무슨 일이 일어나는지 게시하려고합니다! – user1462038

2

프로그램 상단에 use strictuse warnings을 추가하고 모든 변수를 처음 사용시 my으로 선언해야합니다. 그렇지 않으면 자리를 잡기가 어려운 간단한 실수가 많이 나옵니다.

는 또한 open과 어휘 파일 핸들의에 대한 세 매개 변수를 사용해야하며, 파일 열기에 대한 예외를 확인하기위한 펄 관용구는 open 전화에 or die를 추가하는 것입니다. 성공 경로 폐기물 공간 빈 블록 if 제표를 읽을된다. open 호출 마지막으로, 당신이 CSV 파일을 처리 할 때 간단한 split /,/ 사용에 함정이 많이 있기 때문에 펄 모듈을 사용하는 것이 훨씬 안전이

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

처럼 보일 것입니다. Text::CSV 모듈은 당신을 위해 모든 작업을 수행하고 CPAN 볼 수있다.

당신의 문제는 당신이 되감기 또는 두 번째 중첩 루프에서 다시 동일한 핸들에서 읽기 전에 그것을 다시하지 않는 첫 번째 파일의 마지막에 읽은 점이다. 즉, 해당 파일에서 더 이상 데이터를 읽을 수 없으며 프로그램이 비어있는 것처럼 동작합니다.

동일한 파일을 수백 번 읽는 것만으로도 상응하는 레코드를 쌍으로 만드는 것은 나쁜 전략입니다. 파일이 적당한 크기 인 경우에는 정보를 저장하기 위해 메모리에 데이터 구조를 구축해야한다. 당신이 즉시 지정된 이름에 대응하는 데이터를 검색 할 수 있습니다으로 펄 해시 이상적입니다.

나는 이러한 점을 보여주는 코드 개정판을 작성했습니다. 샘플 데이터가 없으므로 코드를 테스트하는 것은 어색 할 것입니다. 그러나 문제가 계속되면 알려주십시오.

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

고맙습니다. 이 코드를 살펴봄으로써 나는 이것에 대해 어떻게해야하는지 더 잘 이해하게되었습니다. 유일한 문제는 CPAN 모듈을 사용할 수 없다는 것입니다. – user1462038

+0

"허용되지 않는"경우, 이는 숙제이며 단순히 "문제가 발생한"문제가 아니라는 것을 의미합니다. 전체 공개는 정중합니다. – mlp

+0

죄송합니다, 아니요. 숙제가 아닙니다. 나는 내가 사용하는 컴퓨터에서 프로그램을 수정할 수 없다. 어쨌든 당신의 견해에 감사드립니다. – user1462038