如何打印Perl二维数组?

时间:2021-01-27 21:30:03

I am trying to write a simple Perl script that reads a *.csv, places the rows of the *.csv file in a two dimensional array, and then prints on item out of the array and then prints a row of the array.

我正在尝试编写一个简单的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";

When I run this script I receive the following error and nothing prints:

当我运行此脚本时,我收到以下错误,没有打印:

Can't use string ("1") as an ARRAY ref while "strict refs" in use at ./scripts.pl line 16.

在./scripts.pl第16行使用“strict refs”时,不能使用字符串(“1”)作为ARRAY引用。

I have looked in a number of other forums and am still not sure how to fix this issue. Can anyone help me fix this script?

我已经查看过其他一些论坛,但仍然不确定如何解决这个问题。任何人都可以帮我修复这个脚本吗?

6 个解决方案

#1


10  

You aren't creating a two-dimensional array (an AoA or "Array of Arrays" in Perl-parlance). This line:

您不是在Perl-parlance中创建二维数组(AoA或“数组数组”)。这一行:

push(@table, @row);

appends the data in @row to @table. You need to push a reference instead, and create a new variable each time through the loop so that you don't push the same reference repeatedly:

将@row中的数据附加到@table。您需要推送引用,并在每次循环时创建一个新变量,这样就不会重复推送相同的引用:

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

While using split is okay for trivial CSV files, it's woefully inadequate for anything else. Use a module like Text::CSV_XS instead:

虽然使用拆分对于普通的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";

#2


3  

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

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

prints

版画

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

Edit: I'll let others get the credit for catching the wrong push.

编辑:我会让其他人因为错误的推动而获得荣誉。

#3


2  

You need 2 changes:

您需要进行2项更改:

  1. use local variable for row
  2. 使用局部变量行
  3. use references for array you put into @table
  4. 使用您放入@table的数组的引用

So your program should look this:

所以你的程序应该是这样的:

#!/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";       

#4


2  

If you call push with list arguments, you append the first list with the remaining list(s) in stack wise fashion. Read about push at Perldoc. So your call of push(@table, @row); is creating a longer @table list, not a two dimensional array.

如果使用list参数调用push,则以堆栈方式追加第一个列表以及剩余列表。阅读有关推动Perldoc的信息。所以你的推送电话(@table,@ run);正在创建一个更长的@table列表,而不是二维数组。

You have received several posts that pushing a list reference to @row as \@row will create a list of rows, and indeed that works. I tend to do it a little differently. Of course, with Perl, there is always another way to do it!

您收到了几个帖子,将列表引用推送到@row,因为\ @row将创建一个行列表,这确实有效。我倾向于这样做有点不同。当然,使用Perl,总有另一种方法可以做到!

Syntactically, you can also push an anonymous array reference into the scalar element of a list to create multi dimension list. The most important thing to know about references in Perl is: 1) they are a scalar and 2) they can refer to anything in Perl - code, array, hash, another reference. Spend some time with the Perl Ref Tutorial and this will become more clear. With your code, just add [ ] around the element you want to be the 2nd dimension in your list, so push(@table, @row); should be push(@table, [ @row ]); In the same sense, you put [ ] around your split so that it becomes push(@table, [ split(/\s*,\s*/, $_) ]); This will simultaneously perform the split and create an anonymous array to the result.

从语法上讲,您还可以将匿名数组引用推送到列表的标量元素以创建多维列表。了解Perl中的引用最重要的是:1)它们是标量; 2)它们可以引用Perl中的任何内容 - 代码,数组,哈希,另一个引用。花一些时间阅读Perl Ref教程,这将变得更加清晰。使用您的代码,只需在您想要成为列表中第二维的元素周围添加[],所以push(@table,@ row);应推(@table,[@ run]);在同样的意义上,你将[]放在你的分割周围,使它成为推(@table,[split(/ \ s *,\ s * /,$ _)]);这将同时执行拆分并为结果创建一个匿名数组。

The specific issue that you have, how to create and access a multi dimensional list, is also treated very well in Tom Christensen's perllol tutorial The solutions to your specific issues with your code are directly dealt with here.

在Tom Christensen的perllol教程中,您所拥有的具体问题,如何创建和访问多维列表也得到了很好的处理。您的代码中的特定问题的解决方案将直接在此处理。

Rewriting your code with the the exact code from Tom's example in perllol, it becomes this:

使用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

#5


1  

Maybe this is what you actually want:

也许这就是你真正想要的:

#!/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";

#6


0  

Change

更改

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

Then it prints out ok.

然后打印好了。

#1


10  

You aren't creating a two-dimensional array (an AoA or "Array of Arrays" in Perl-parlance). This line:

您不是在Perl-parlance中创建二维数组(AoA或“数组数组”)。这一行:

push(@table, @row);

appends the data in @row to @table. You need to push a reference instead, and create a new variable each time through the loop so that you don't push the same reference repeatedly:

将@row中的数据附加到@table。您需要推送引用,并在每次循环时创建一个新变量,这样就不会重复推送相同的引用:

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

While using split is okay for trivial CSV files, it's woefully inadequate for anything else. Use a module like Text::CSV_XS instead:

虽然使用拆分对于普通的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";

#2


3  

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

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

prints

版画

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

Edit: I'll let others get the credit for catching the wrong push.

编辑:我会让其他人因为错误的推动而获得荣誉。

#3


2  

You need 2 changes:

您需要进行2项更改:

  1. use local variable for row
  2. 使用局部变量行
  3. use references for array you put into @table
  4. 使用您放入@table的数组的引用

So your program should look this:

所以你的程序应该是这样的:

#!/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";       

#4


2  

If you call push with list arguments, you append the first list with the remaining list(s) in stack wise fashion. Read about push at Perldoc. So your call of push(@table, @row); is creating a longer @table list, not a two dimensional array.

如果使用list参数调用push,则以堆栈方式追加第一个列表以及剩余列表。阅读有关推动Perldoc的信息。所以你的推送电话(@table,@ run);正在创建一个更长的@table列表,而不是二维数组。

You have received several posts that pushing a list reference to @row as \@row will create a list of rows, and indeed that works. I tend to do it a little differently. Of course, with Perl, there is always another way to do it!

您收到了几个帖子,将列表引用推送到@row,因为\ @row将创建一个行列表,这确实有效。我倾向于这样做有点不同。当然,使用Perl,总有另一种方法可以做到!

Syntactically, you can also push an anonymous array reference into the scalar element of a list to create multi dimension list. The most important thing to know about references in Perl is: 1) they are a scalar and 2) they can refer to anything in Perl - code, array, hash, another reference. Spend some time with the Perl Ref Tutorial and this will become more clear. With your code, just add [ ] around the element you want to be the 2nd dimension in your list, so push(@table, @row); should be push(@table, [ @row ]); In the same sense, you put [ ] around your split so that it becomes push(@table, [ split(/\s*,\s*/, $_) ]); This will simultaneously perform the split and create an anonymous array to the result.

从语法上讲,您还可以将匿名数组引用推送到列表的标量元素以创建多维列表。了解Perl中的引用最重要的是:1)它们是标量; 2)它们可以引用Perl中的任何内容 - 代码,数组,哈希,另一个引用。花一些时间阅读Perl Ref教程,这将变得更加清晰。使用您的代码,只需在您想要成为列表中第二维的元素周围添加[],所以push(@table,@ row);应推(@table,[@ run]);在同样的意义上,你将[]放在你的分割周围,使它成为推(@table,[split(/ \ s *,\ s * /,$ _)]);这将同时执行拆分并为结果创建一个匿名数组。

The specific issue that you have, how to create and access a multi dimensional list, is also treated very well in Tom Christensen's perllol tutorial The solutions to your specific issues with your code are directly dealt with here.

在Tom Christensen的perllol教程中,您所拥有的具体问题,如何创建和访问多维列表也得到了很好的处理。您的代码中的特定问题的解决方案将直接在此处理。

Rewriting your code with the the exact code from Tom's example in perllol, it becomes this:

使用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

#5


1  

Maybe this is what you actually want:

也许这就是你真正想要的:

#!/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";

#6


0  

Change

更改

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

Then it prints out ok.

然后打印好了。