如何将CSV文件中的数据放入Perl哈希

时间:2013-06-26 09:48:09

标签: perl csv hash

我有Perl和CSV文件,例如:

"Name","Lastname"
"Homer","Simpsons"
"Ned","Flanders"

在这个CSV文件中,我在第一行有标题,在其他行有 数据

我想将此CSV文件转换为此类Perl数据:

[
    {
        Lastname => "Simpsons",
        Name     => "Homer",
    },
    {
        Lastname => "Flanders",
        Name     => "Ned",
    },
]

我编写了用户Text::CSV并执行我需要的功能。 以下是示例脚本:

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';
use 5.010;
use utf8;
use open qw(:std :utf8);

use Text::CSV;

sub read_csv {
    my ($filename) = @_;

    my @first_line;
    my $result;

    my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1 });
    open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
    while (my $row = $csv->getline ($fh)) {
        if (not @first_line) {
            @first_line = @{$row};
        } else {
            push @{$result}, { map { $first_line[$_] => $row->[$_] } 0..$#first_line };
        }
    }
    close $fh;

    return $result;
}

my $data = read_csv('sample.csv');

这很好用,但是这个函数我想在几个脚本中使用。我 非常惊讶Text :: CSV没有此功能。

我的问题。我该怎么做才能在将来简化这些任务的解决 我和其他人?

我应该从CPAN使用一些Perl模块,我应该尝试添加此功能吗? Text :: CSV,还是别的什么?

2 个答案:

答案 0 :(得分:3)

咦?为什么这么复杂?首先,我们在循环之外获取标题:

my $headers = $csv->getline($fh) or die "no header";

将这些分配为列名:

$csv->column_names(@$headers);

然后,每次调用getline_hr都会提供一个hashref:

while (my $hashref = $csv->getline_hr($fh)) {
  push @$result, $hashref;
}

我们也可以使用getline_hr_all

$result = $csv->getline_hr_all($fh);

换句话说,它并不复杂,大多数作品已由Text::CSV提供,并且可以在很少的行中完成。

此外,这样的模块似乎已经存在:Text::CSV::Slurp。 (注意:通过metacpan进行反向依赖搜索非常棒)

答案 1 :(得分:0)

这可能不是标准功能,因为不同的人会希望将他们的CSV文件解析为不同的数据结构。

为什么不创建自己的包装此功能的模块?

package CSVRead;

use strict;
use warnings;
use 5.010;
use open qw(:std :utf8);

use Text::CSV;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(read_csv);

sub read_csv {
    my ($filename) = @_;

    my @first_line;
    my $result;

    my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1 });
    open my $fh, "<:encoding(utf8)", $filename or die "$filename: $!";
    while (my $row = $csv->getline ($fh)) {
        if (not @first_line) {
            @first_line = @{$row};
        } else {
            push @{$result}, { map { $first_line[$_] => $row->[$_] } 0..$#first_line };
        }
    }
    close $fh;

    return $result;
}

然后,像这样使用它:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;
use CSVRead;

my $data = read_csv('sample.csv');

say Dumper $data;