我正在尝试编写一个简单的Perl脚本,它读取* .csv,将* .csv文件的行放在二维数组中,然后打印出数组中的项目,然后打印一行阵列。
#!/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";
当我运行此脚本时,我收到以下错误,并且没有打印:
在./scripts.pl第16行使用“strict refs”时,不能使用字符串(“1”)作为ARRAY引用。
我已经查看过其他一些论坛,但我仍然不确定如何解决这个问题。任何人都可以帮我修复这个脚本吗?
答案 0 :(得分:10)
您不是在Perl-parlance中创建二维数组(AoA或“数组数组”)。这一行:
push(@table, @row);
将@row
中的数据附加到@table
。你需要推送一个引用,并在每次循环时创建一个新变量,这样你就不会重复推送相同的引用:
my @table;
while(<CSV>) {
my @row = split(/\s*,\s*/, $_);
push(@table, \@row);
}
虽然使用split
对于琐碎的CSV文件是可以的,但是对于其他任何东西来说都是不合适的。请改用Text::CSV_XS之类的模块:
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";
答案 1 :(得分:3)
my @arr = ( [a, b, c],
[d, e, f],
[g, h, i],
);
for my $row (@arr) {
print join(",", @{$row}), "\n";
}
打印
a,b,c
d,e,f
g,h,i
编辑:我会让其他人因为抓错而获得赞誉。
答案 2 :(得分:2)
您需要进行2次更改:
@table
所以你的程序应该看起来像这样:
#!/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";
答案 3 :(得分:2)
如果使用list参数调用push,则以堆栈方式追加第一个列表以及剩余列表。阅读Perldoc处的推送信息。因此,您对push(@table, @row);
的调用是创建一个较长的@table
列表,而不是二维数组。
您收到了几篇推送列表引用@row
的帖子,因为\@row
会创建一个行列表,这确实有用。我倾向于做一点不同的事情。当然,使用Perl,总有另一种方法可以做到!
从语法上讲,您还可以将匿名数组引用推送到列表的标量元素以创建多维列表。了解Perl中的引用最重要的是:1)它们是标量; 2)它们可以引用Perl中的任何内容 - 代码,数组,哈希,另一个引用。花一些时间与Perl Ref Tutorial一起,这将变得更加清晰。使用您的代码,只需在您希望成为列表中第二维的元素周围添加[ ]
,因此push(@table, @row);
应该是push(@table, [ @row ]);
同样,您放置[ ]
在你的拆分周围,它变成push(@table, [ split(/\s*,\s*/, $_) ]);
这将同时执行拆分并为结果创建一个匿名数组。
在Tom Christensen的perllol tutorial中,您所拥有的特定问题,如何创建和访问多维列表也得到了很好的处理。您的代码的具体问题的解决方案将直接在此处理。
使用perllol中Tom的示例中的确切代码重写代码,它就变成了:
#!/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,00123
答案 4 :(得分:1)
也许这就是你真正想要的东西:
#!/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";
答案 5 :(得分:0)
更改
#push(@table, @row);
push(@table, \@row); #push a reference to the array into each cell in @table.
然后打印出来。