2012-06-17 29 views
6

Tôi là tương đối mới đối với Perl và tôi đã đi qua dự án này mà tôi đang có một chút thời gian khó khăn với. Đối tượng của dự án là so sánh hai tệp csv, một trong số đó sẽ chứa: $ name, $ model, $ version và khác chứa: $ name2, $ disk, $ storage vào cuối Tệp RESULT sẽ chứa các dòng phù hợp đó và gộp các thông tin như vậy: $ name, $ model, $ version, $ disk, $ storage.bỏ qua một dòng trong một mảng, Perl

Tôi đã cố gắng thực hiện việc này, nhưng vấn đề của tôi là khi một trong các yếu tố thiếu chương trình bị hỏng. Khi nó gặp một dòng trong tập tin thiếu một phần tử nó dừng lại ở dòng đó. Làm cách nào để khắc phục sự cố này? bất kỳ đề xuất hoặc một cách để làm thế nào tôi có thể làm cho nó bỏ qua dòng đó và tiếp tục?

Dưới đây là mã của tôi:

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

Trong lần tiếp theo, hãy sử dụng nghiêm ngặt mã của bạn để bảo vệ bạn trước các lỗi gây phiền nhiễu. –

+0

Vui lòng 'sử dụng nghiêm ngặt;', 'sử dụng cảnh báo;', thụt lề mã của bạn đúng cách, sử dụng phiên bản đối số mở bằng tập tin từ vựng và tìm hiểu cách sử dụng các hàm mảng ('push, map, grep'). – dgw

+1

Bất cứ tài liệu nào bạn đang sử dụng để tự mình dạy Perl, tôi khuyên bạn nên bỏ chúng - mã của bạn dựa trên các mẫu chỉ đơn giản là lỗi thời (xử lý tập tin toàn cục, dạng mở 2-arg). Xin vui lòng không dùng cá nhân này - nó rõ ràng không phải là lỗi của bạn, nhưng bạn sẽ được RẤT VERY phục vụ tốt bằng cách học hỏi từ nhiều hơn và hiện đại hơn sách/hướng dẫn/mã ví dụ hơn những gì bạn đang sử dụng rõ ràng. – DVK

Trả lời

2

Tôi nghĩ rằng bạn muốn next, cho phép bạn hoàn thành lặp hiện ngay lập tức và bắt đầu tiếp theo một:

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

Điều kiện mà bạn sử dụng phụ thuộc vào những gì giá trị bạn sẽ chấp nhận. Trong ví dụ của tôi, tôi giả định rằng tất cả các giá trị cần phải đúng. Nếu họ cần phải chỉ không phải là chuỗi rỗng, có thể bạn kiểm tra độ dài thay vì:

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

Nếu bạn biết làm thế nào để xác nhận từng lĩnh vực, bạn có thể có chương trình con cho những người:

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

sub is_valid_model { ... } 

Bây giờ bạn chỉ cần quyết định cách tích hợp vào những gì bạn đang làm.

+0

Cảm ơn bạn rất nhiều cho đầu vào của bạn. Tôi sẽ cố gắng để làm lại mã của tôi với điều này và đăng lên những gì sẽ xảy ra! – user1462038

2

Bạn nên bắt đầu bằng cách thêm use strictuse warnings vào đầu chương trình và khai báo tất cả biến với my tại thời điểm sử dụng đầu tiên của chúng. Điều đó sẽ tiết lộ rất nhiều lỗi đơn giản mà nếu không sẽ khó phát hiện.

Bạn cũng nên sử dụng ba tham số cho số open và tập tin từ vựng, và thành ngữ Perl để kiểm tra ngoại lệ khi mở tệp là thêm or die vào cuộc gọi open. if câu lệnh có khối trống cho không gian lãng phí đường dẫn thành công và không thể đọc được. Một open gọi nên giống như thế này

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

Cuối cùng, nó là an toàn hơn nhiều để sử dụng một mô-đun Perl khi bạn đang xử lý file CSV vì có rất nhiều cạm bẫy trong việc sử dụng một cách đơn giản split /,/. Mô-đun Text::CSV đã thực hiện tất cả công việc cho bạn và có sẵn trên CPAN.

Bạn có vấn đề là, khi đọc đến cuối tập tin đầu tiên, bạn không tua lại hoặc mở lại nó trước khi đọc từ cùng một tay cầm một lần nữa trong vòng lặp lồng nhau thứ hai. Điều đó có nghĩa là không có thêm dữ liệu nào được đọc từ tệp đó và chương trình sẽ hoạt động như thể nó trống.

Đó là một chiến lược xấu để đọc qua cùng một tệp hàng trăm lần chỉ để ghép nối các bản ghi coresponding. Nếu tệp có kích thước hợp lý, bạn nên xây dựng cấu trúc dữ liệu trong bộ nhớ để giữ thông tin. Một hàm băm Perl lý tưởng vì nó cho phép bạn tra cứu dữ liệu tương ứng với một tên đã cho ngay lập tức.

Tôi đã viết bản sửa đổi mã của bạn thể hiện những điểm này. Nó sẽ là khó khăn cho tôi để kiểm tra mã như tôi không có dữ liệu mẫu, nhưng nếu bạn tiếp tục có vấn đề xin vui lòng cho chúng tôi biết.

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

Cảm ơn bạn rất nhiều vì điều này! từ việc xem xét mã này, tôi hiểu rõ hơn về cách tôi nên thực hiện điều này. Vấn đề duy nhất là tôi không được phép sử dụng các mô-đun CPAN. – user1462038

+0

Nếu bạn "không được phép", thì điều đó cho thấy đây là bài tập về nhà và không chỉ đơn thuần là một vấn đề mà bạn "gặp phải". Việc tiết lộ hoàn toàn chỉ là lịch sự. – mlp

+0

Tôi xin lỗi, không. Đây không phải là bài tập về nhà. Tôi chỉ đơn giản là không được phép sửa đổi các chương trình trên máy tính tôi sử dụng. Cảm ơn bạn đã xem. – user1462038

Các vấn đề liên quan