Неопределенные значения из CSV-файла дают нежелательный результат - PullRequest
0 голосов
/ 29 марта 2019

У меня есть 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

Я анализирую этот файл и хочу получить некоторые значения из файла.Я хочу только те имена из первой строки, для которых соответствующее значение присутствует во 2-й строке.Означает, что я хочу получить Memory, Extra 1 и Extra 2, поскольку соответствующее значение присутствует во 2-й строке (d, h и b).Для чего я делаю, я храню значения обеих строк в отдельных массивах, а затем перебираю массив для 2-й строки и индексы, соответствующие значению которого присутствует в этом соответствующем значении индекса, который я беру из 1-го массива.и сохраняю его во втором массиве. Код, который я использую, -

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.Может кто-нибудь сказать мне, что я делаю неправильно в коде ??

РЕДАКТИРОВАТЬ: Когда я меняю 2-й ряд на ", d ,,," и следуя методу @Dada, то этодолжен брать только «Память» из 1-го ряда, но вместо этого он берет все после памяти, то есть Память, Кодирование, Дополнительный предохранитель1, Дополнительный предохранитель2

И затем я напечатал длину массива @filter.В идеале это должно быть 5 с 1 определенным значением и 4 с другими неопределенными значениями, но, как ни странно, длина @filter оказалась равной 2. Это действительно сбивает с толку.

1 Ответ

6 голосов
/ 29 марта 2019

Ваш код довольно плох по нескольким причинам. Вместо того, чтобы пытаться их исправить, что привело бы к плохому, но работающему коду, я собираюсь указать на них и предложить лучший способ.

  • Вы сначала 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 /,/. (последний будет неправильно работать с полями в кавычках, содержащими запятые или символы новой строки (и, вероятно, имеет другие проблемы, о которых я сейчас не думаю))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...