我从一个CSV文件中读取数据,并根据Key-Value Pairs填充一个Hash,记录的第一列是Key,其余的记录是value。然而,对于某些文件,我需要将前两列作为Key,其余的记录为value。我根据以下内容写成了 if
循环,但我想知道是否有更好的方法?
use strict;
use warnings;
open my $fh, '<:encoding(utf8)', 'Sample.csv'
or die "Couldn't open Sample.csv";
my %hash;
my $KeyCols=2;
while (<$fh>) {
chomp;
if ($KeyCols==1) {
next unless /^(.*?),(.*)$/;
$hash{$1} = $2;
}
elsif ($KeyCols==2) {
next unless /^(.*?),(.*?),(.*)$/;
$hash{$1.$2} = $3;
}
}
这里有一种方法允许任何数量的键列(不只是1或2),但它使用的是 split
而不是regex。
use warnings;
use strict;
my %hash;
my $KeyCols = 2;
while (<DATA>) {
chomp;
my @cols = split /,/, $_, $KeyCols+1;
next unless @cols > $KeyCols;
my $v = pop @cols;
my $k = join '', @cols;
$hash{$k} = $v;
}
__DATA__
a,b,c,d,e,f
q,w,e,r,t,y
这是一个自成一体的代码示例。
一个重要的假设是,你的CSV文件中的数据本身不包含逗号。 你应该使用一个CSV解析器,如 Text::CSV 反正。
也许最好在代码的第一行定义变量--否则你必须在代码中定义 跳跃 遍布整个代码。
您可以定义 检索词 基于你 $KeyCols
和处理代码将与以前一样。
use strict;
use warnings;
use feature 'say';
my $KeyCols = 2;
my $fname = 'Sample.csv';
my %hash;
my $re;
if( $KeyCols == 2 ) {
$re = qr/^(.*?,.*?),(.*)$/
} else {
$re = qr/^(.*?),(.*)$/;
}
open my $fh, '<:encoding(utf8)', $fname
or die "Couldn't open $fname";
while (<$fh>) {
chomp;
next unless /$re/;
$hash{$1} = $2;
}
close $fh;