我有一个名为
的CSV文件Sample.csv,如下所示 Name,Memory,Encoding,Extra 1,Extra 2
,d,,h,b
FUSE_1,36,30,37,15
FUSE_1,36,28,36,31
Name1,1TB,00000001,30,010
Name1,1TB,00000010,52,001
我正在解析此文件,并希望从文件中检索一些值。我想要的只是第一行中的那些名称,而第二行中具有相应的值。意味着我想获得Memory,Extra 1和Extra 2,因为第二行(d,h和b)中存在相应的值。为此,我将两行的值存储在单独的数组中,然后遍历第二行的数组以及与该值相对应的索引,该索引是我从第一数组获取的并将其存储在第二个数组中。我正在使用的代码是-
my $iniFilename = "Sample.csv";
open(my $fi,'<',$iniFilename) or die "Can't open $iniFilename";
while(my $row=<$fi>){
if($row_no == 0)
{
chomp($row);
$row=~ s/\A\s+//g;
$row=~s/\R//g;
if(length($row))
{
@fuse_name_initial = split(/,/,$row);
}
}
elsif($row_no == 1)
{
chomp($row);
$row=~ s/\A\s+//g;
$row=~s/\R//g;
if(length($row)){
@fuse_data_type_initial =split(/,/,$row);
}
}
$row_no++;
}
my $trace=0;
foreach (@fuse_data_type_initial)
{
if($_)
{
if($fuse_name_initial[$trace] !~ /Extra Fuse/){
push @column_no_for_fuse_value,($trace+1);
push @fuse_names , $fuse_name_initial[$trace];
push @fuse_data_type ,$_ ;
$trace++;
}
else{
push @extra_fuse_data_type ,$_ ;
$trace++;
}
}
}
现在,我期望@fuse_names数组将名称“ Memory”反映为“ Extra Fuse1”,而“ Extra Fuse2”使用正则表达式过滤掉,但结果却非常糟糕。我在@ fuse_names- Name,Memory,Encoding中得到了三个元素。有人可以告诉我代码中我在做什么错吗?
编辑:当我将第二行更改为“,d ,,”并遵循@Dada方法时,它只应从第一行获取“ Memory”,但它将占用内存之后的所有内容,即Memory,Encoding,Extra Fuse1 ,额外保险丝2
然后我打印了@filter数组的长度。理想情况下,它应该是5,带有1个定义值和4个其他undef值,但是奇怪的是@filter的长度是2。这确实令人困惑。
答案 0 :(得分:6)
您的代码非常糟糕,原因有几个。我将尝试指出它们,而不是试图修复它们,这会给您留下糟糕但可以正常工作的代码,并提出一种更好的方法。
仅当您对前两行感兴趣时,您首先while(my $row = <$fi>)
遍历整个文件。您应该只使用<$fi>
两次来读取前两行:
my $headers = <$fi>;
my $filters = <$fi>;
您不应重复代码。特别是你写了两次
chomp($row);
$row=~ s/\A\s+//g;
$row=~s/\R//g;
您可能只是在一会儿就放了一次。
与$trace++
相同:您希望在foreach
循环的每次迭代中都完成此操作;没有理由将其放在if
的末尾和else
的末尾。
始终 use strict
和use warnings
。
这是我建议的:
use strict; # Always use strict and warnings!
use warnings;
my $iniFilename = "Sample.csv";
open(my $fi,'<',$iniFilename) or die "Can't open $iniFilename";
my @headers = split ',', <$fi> =~ s/\A\s+|\s+\Z//gr, -1;
my @filter = split ',', <$fi> =~ s/\A\s+|\s+\Z//gr, -1;
for my $i (0 .. $#filter) {
$headers[$i] = undef if !$filter[$i] || $filter[$i] eq "" ;
}
# @headers now contains (undef, "Memory", undef, "Extra 1", "Extra 2")
如果您需要@headers
以外的undef
索引:
my @headers_indices = grep { defined $headers[$_] } 0 .. $#headers;
如果仅需要非undef标头的名称:
my @non_undef_headers = grep { defined $_ } @headers;
最后,由于您要解析CSV文件,因此您可能希望使用CSV解析器(例如Text::CSV_XS),而不是split /,/
。 (后者会错误地引用包含逗号或换行符的字段(并且可能还有其他我现在不在考虑的问题))