2010-06-10 43 views
8

Tôi đang cố gắng viết một kịch bản Perl đơn giản đọc một tệp * .csv, đặt các hàng của tệp * .csv trong một mảng hai chiều và sau đó in trên mục ra khỏi mảng và sau đó in một hàng của mảng .Làm thế nào để in một mảng 2 chiều Perl?

#!/usr/bin/perl 
use strict; 
use warnings; 

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!"); 
my @row; 
my @table; 

while(<CSV>) { 
     @row = split(/\s*,\s*/, $_); 
     push(@table, @row); 
} 
close CSV || die $!; 

foreach my $element (@{ $table[0] }) { 
    print $element, "\n"; 
} 

print "$table[0][1]\n"; 

Khi tôi chạy kịch bản này tôi nhận được báo lỗi và không in sau:

Không thể sử dụng chuỗi ("1") như một ref ARRAY khi "refs nghiêm ngặt" sử dụng ở. /scripts.pl line 16.

Tôi đã xem xét một số diễn đàn khác và tôi vẫn không biết cách khắc phục sự cố này. Bất cứ ai có thể giúp tôi sửa kịch bản này?

+3

+1 cho không lãng phí thời gian của mọi người bằng cách bỏ qua 'use strict; sử dụng cảnh báo; – Ether

+1

Bạn thực sự nên tránh 2 đối số 'mở'. Nó có một số vấn đề tốt nhất để tránh (để thảo luận xem bài đăng perlmonks 2001 này: http://www.perlmonks.org/?node_id=131085) Xem bài đăng SO này để biết thông tin về xử lý từ vựng: http: // stackoverflow .com/questions/613906/why-does-programming-perl-use-local-not-my-for-filehandles – daotoad

+1

Xem ['perldoc perllol'] (http://perldoc.perl.org/perllol.html#Access -and-In ấn) - Truy cập và in – Zaid

Trả lời

10

Bạn không tạo mảng hai chiều (một AoA hoặc "Mảng mảng" trong Perl-parlance). Dòng này:

push(@table, @row); 

nối dữ liệu vào @row đến @table. Bạn cần phải đẩy một tham chiếu thay vào đó, và tạo ra một biến mới mỗi lần thông qua các vòng lặp để bạn không đẩy tham chiếu cùng nhiều lần:

my @table; 
while(<CSV>) { 
    my @row = split(/\s*,\s*/, $_); 
    push(@table, \@row); 
} 

Trong khi sử dụng split là okay cho các tập tin CSV tầm thường, nó rất không thỏa đáng cho bất cứ điều gì khác. Sử dụng một mô-đun như Text::CSV_XS thay vì:

use strict; 
use warnings; 
use Text::CSV_XS; 

my $csv = Text::CSV_XS->new() or die "Can't create CSV parser.\n"; 
my $file = shift @ARGV   or die "No input file.\n"; 
open my $fh, '<', $file  or die "Can't read file '$file' [$!]\n"; 

my @table; 
while (my $row = $csv->getline($fh)) { 
    push @table, $row; 
} 
close $fh; 

foreach my $row (@table) { 
    foreach my $element (@$row) { 
     print $element, "\n"; 
    } 
} 

print $table[0][1], "\n"; 
+0

Mảng-mảng là danh pháp chính xác. Thực sự không có thứ gì như danh sách liệt kê trong Perl. (Tên của trang mặc định 'perllol'. Tuy nhiên, hãy viết tắt là – friedo

+3

+1 để sử dụng Văn bản :: CSV; nó thực sự là ngớ ngẩn để không. –

+0

@friedo: Điểm được chụp. Tôi đã nhìn thấy LoL được sử dụng nhiều lần nhưng đó không phải là cái cớ để truyền bá quan niệm sai lầm. Đã sửa. –

3
my @arr = ([a, b, c], 
      [d, e, f], 
      [g, h, i], 
     ); 

for my $row (@arr) { 
    print join(",", @{$row}), "\n"; 
} 

in

a,b,c 
d,e,f 
g,h,i 

Edit: Tôi sẽ cho người khác có được tín dụng cho việc đánh bắt push sai.

2

Bạn cần 2 thay đổi:

  1. sử dụng biến cục bộ cho hàng
  2. tài liệu tham khảo sử dụng cho mảng bạn đưa vào @table

Vì vậy, chương trình của bạn nên xem xét điều này:

#!/usr/bin/perl 
use strict; 
use warnings; 

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!"); 
my @table; 

while(<CSV>) { 
    my @row = split(/\s*,\s*/, $_); 
    push(@table, \@row); 
} 
close CSV || die $!; 

foreach my $element (@{ $table[0] }) { 
    print $element, "\n"; 
} 

print "$table[0][1]\n";  
1

Có thể đây là những gì bạn thực sự muốn:

#!/usr/bin/perl 
use strict; 
use warnings; 

open(CSV, $ARGV[0]) || die("Cannot open the $ARGV[0] file: $!"); 
my @table; 

while(<CSV>) { 
     my @row = split(/\s*,\s*/, $_); 
     push(@table, \@row); 
} 
close CSV || die $!; 

foreach my $element (@{ $table[0] }) { 
    print $element, "\n"; 
} 

print "$table[0][1]\n"; 
+0

sẽ tốt hơn nếu sử dụng hình thức mở hiện đại: mở ($ csv, '<', $ ARGV [0]) –

0

Thay đổi

#push(@table, @row); 
push(@table, \@row); #push a reference to the array into each cell in @table. 

Sau đó nó in ra ok.

+0

... nhưng điều sai trái của '@row 'không được tạo bên trong vòng lặp. –

+0

... nhưng nó có thể được sửa nếu bạn nói 'push @table, [@row]' để sử dụng tham chiếu đến bản sao của '@ row'. – mob

2

Nếu bạn gọi push với các đối số danh sách, bạn thêm danh sách đầu tiên với danh sách còn lại (s) trong ngăn xếp thời trang khôn ngoan. Đọc về đẩy tại Perldoc. Vì vậy, cuộc gọi của bạn là push(@table, @row); đang tạo danh sách dài hơn @table, không phải là mảng hai chiều.

Bạn đã nhận được một số bài đăng đẩy danh sách tham chiếu đến @row dưới dạng \@row sẽ tạo danh sách các hàng và thực sự hoạt động. Tôi có xu hướng làm điều đó một chút khác biệt.Tất nhiên, với Perl, luôn luôn có một cách khác để làm điều đó!

Cú pháp, bạn cũng có thể đẩy tham chiếu mảng ẩn danh vào phần tử vô hướng của danh sách để tạo danh sách nhiều thứ nguyên. Điều quan trọng nhất cần biết về các tham chiếu trong Perl là: 1) chúng là một vô hướng và 2) chúng có thể tham chiếu đến bất kỳ thứ gì trong Perl - mã, mảng, băm, một tham chiếu khác. Hãy dành một chút thời gian với Perl Ref Tutorial và điều này sẽ trở nên rõ ràng hơn. Với mã của bạn, chỉ cần thêm [ ] quanh phần tử bạn muốn là thứ nguyên thứ 2 trong danh sách của bạn, do đó, push(@table, @row); phải là push(@table, [ @row ]); Theo cùng một nghĩa, bạn đặt [ ] xung quanh phần tách của mình để nó trở thành push(@table, [ split(/\s*,\s*/, $_) ]);. một mảng ẩn danh cho kết quả.

Vấn đề cụ thể mà bạn có, cách tạo và truy cập danh sách đa chiều, cũng được xử lý rất tốt trong các giải pháp cụ thể với mã của bạn được giải quyết trực tiếp tại đây của Tom Christensen perllol tutorial.

Viết lại mã của bạn với các mã chính xác từ ví dụ của Tom trong perllol, nó trở nên này:

#!/usr/bin/perl 
use strict; 
use warnings; 

my (@row, @table, $n, $rowref); 

while(<DATA>) { 
     chomp; 
     # regex to separate CSV (use of a cpan module for CSV STRONGLY advised... 
     @row = /(?:^|,)("(?:[^"]+|"")*"|[^,]*)/g; 
     for (@row) { 
      if (s/^"//) { s/"$//; s/""/"/g; } 
     } 
     push(@table, [ @row ]); #Note the [ ] around the list 
} 

# Now the table is created, print it: 
my $rowcnt=0; 
foreach $rowref (@table) { 
    print "row $rowcnt:\n"; 
    $rowcnt++; 
    print " [ @$rowref ], \n"; 
} 

# You can access the table in the classic [i][j] form: 
for my $i (0 .. $#table) { 
    $rowref = $table[$i]; 
    $n = @$rowref - 1; 
    for my $j (0 .. $n) { 
     print "element $i, $j of table is $table[$i][$j]\n"; 
    } 
} 

# You can format it: 
for my $i (0 .. $#table) { 
    print "$table[$i][0] $table[$i][1]\n"; 
    print "$table[$i][2]\n"; 
    print "$table[$i][3], $table[$i][4] $table[$i][5]\n\n"; 
} 


__DATA__ 
Mac,Doe,120 jefferson st.,Riverside, NJ, 08075 
Jack,McGinnis,220 hobo Av.,Phila, PA,09119 
"John ""Da Man""",Repici,120 Jefferson St.,Riverside, NJ,08075 
Stephen,Tyler,"7452 Terrace ""At the Plaza"" road",SomeTown,SD, 91234 
,Blankman,,SomeTown, SD, 00298 
"Joan ""Joan, the bone""",Jett,"9th, at Terrace plc",Desert City,CO,0
Các vấn đề liên quan