2013-06-26 36 views
0

我有Perl和CSV的東西,如文件:如何把從CSV文件數據的Perl哈希

"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還是其他?

+0

我聯繫''文本:: CSV''的作者,並問他是否會接受一個補丁。如果您創建自己的模塊,您將獨自負責保持它的最新狀態。從作者名單來看,這個模塊似乎正在積極維護。 – mzedeler

+0

不管,如果你把它放在CPAN的,你知道如何創建pacakges以及它們是如何工作的,或者是你更多做正確的事情看,並沒有怎麼辦呢? – simbabque

回答

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是真棒)

+0

謝謝你在metacpan中使用逆向依賴的想法。我已經知道這個功能,但是我沒有意識到在這個問題中使用它。是的,現有模塊的使用是最好的選擇。 – bessarabov

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;