0

我有 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 还是其他什么?

4

2 回答 2

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 进行反向依赖搜索很棒)

于 2013-06-26T10:50:41.103 回答
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;
于 2013-06-26T10:54:18.633 回答