CSV文件中的undef值导致不良结果

时间:2019-03-29 15:17:41

标签: perl

我有一个名为

的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。这确实令人困惑。

1 个答案:

答案 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 strictuse 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 /,/。 (后者会错误地引用包含逗号或换行符的字段(并且可能还有其他我现在不在考虑的问题))