Как распечатать Perl 2-мерный массив? - PullRequest
8 голосов
/ 11 июня 2010

Я пытаюсь написать простой 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";

Когда я запускаю этот скрипт, я получаю следующую ошибку, и ничего не печатается:

Невозможно использовать строку ("1") в качестве ссылки на массив во время "строгие ссылки "используется в ./scripts.pl строка 16.

Я просматривал ряд других форумов и до сих пор не уверен, как решить эту проблему.Может кто-нибудь помочь мне исправить этот скрипт?

Ответы [ 6 ]

10 голосов
/ 11 июня 2010

Вы не создаете двумерный массив (AoA или «Массив массивов» на языке Perl).Эта строка:

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";
3 голосов
/ 11 июня 2010
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 голосов
/ 11 июня 2010

Если вы вызываете push с аргументами списка, вы добавляете первый список с остальными списками в стеке.Читайте о 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*/, $_) ]); Это одновременно выполнит разделение и создаст анонимный массив для результата.

Конкретная проблема, с которой вы сталкиваетесь, как создавать многомерный список и получать к нему доступ, также очень хорошо рассматривается в учебнике Тома Кристенсена perllol Решения ваших конкретных проблем с вашим кодом напрямуюздесь.

Переписав свой код с точным кодом из примера Тома в perllol, он становится таким:

#!/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
2 голосов
/ 11 июня 2010

Вам нужно 2 изменения:

  1. использовать локальную переменную для строки
  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";       
1 голос
/ 11 июня 2010

Может быть, это то, что вы на самом деле хотите:

#!/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 голосов
/ 11 июня 2010

Изменение

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

Тогда он печатается нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...