Perl - используйте Data::Dumper для обратной записи в файл

У меня есть большой файл.csv (2 - 3 миллиона записей). Мне нужно объединить первые три поля (с подчеркиванием) и добавить их к каждой записи, затем мне нужно отсортировать файл на основе этого нового поля и трех других полей. Я могу это сделать (сейчас я тестирую его с помощью файла с 4 записями) - но я не уверен, как записать его обратно в файл в той же форме.csv - вместо того, чтобы Data::Dumper форматировал каждый строка как отдельная переменная. Вот код, который у меня есть до сих пор - у меня есть пара строк Print (для вывода на экран), чтобы увидеть, что он делает -

#!/usr/bin/perl/

use strict;
use warnings;
use Data::Dumper;

my $filename = '/testpath/test.csv';
#$filename = 'test.csv';

open my $FH, $filename
  or die "Could not read from $filename <$!>, program halting.";

# Read the header line.
chomp(my $line = <$FH>);
my @fields = split(/,/, $line);
#print "Field Names:\n", Dumper(@fields), $/;
print Dumper(@fields), $/;

my @data;
# Read the lines one by one.
while($line = <$FH>) {

# split the fields, concatenate the first three fields,
# and add it to the beginning of each line in the file
    chomp($line);
    my @fields = split(/,/, $line);
    unshift @fields, join '_', @fields[0..2];
    push @data, \@fields;
}
close $FH;
print "Unsorted:\n", Dumper(@data); #, $/;

@data = sort {
    $a->[0] cmp $b->[0] ||
    $a->[20] cmp $b->[20] ||
    $a->[23] cmp $b->[23] ||
    $a->[26] cmp $b-> [26]
} @data;


open my $OFH, '>', '/testpath/parsedTest.csv';
print $OFH Dumper(@data);
close $OFH;

exit;

Я предполагаю, что это в "print $OFH Dumper(@data);" строка, что мне нужно переформатировать его обратно в исходную форму.

И, пожалуйста, будьте добры, поскольку я новичок.

__________РЕДАКТИРОВАТЬ__________________________________

Вот четыре строки из тестового файла.csv - первая строка - это запись заголовка:

STORE_NBR,CONTROL_NBR,LINE_NBR,SALES_NBR,QTY_MISTINT,REASON_CODE,MISTINT_COMM,SZ_CDE,TINTER_MODEL,TINTER_SERL_NBR,SPECTRO_MODEL,SPECTRO_SERL_NBR,EMP_NBR,TRAN_DATE,TRAN_TIME,CDS_ADL_FLD,PROD_NBR,PALETTE,COLOR_ID,INIT_TRAN_DATE,GALLONS_MISTINTED,UPDATE_EMP_NBR,UPDATE_TRAN_DATE,GALLONS,FORM_SOURCE,UPDATE_TRAN_TIME,SOURCE_IND,CANCEL_DATE,COLOR_TYPE,CANCEL_EMP_NBR,NEED_EXTRACTED,MISTINT_MQ_XTR,DATA_SOURCE,GUID,QUEUE_NAME,BROKER_NAME,MESSAGE_ID,PUT_TIME,CREATED_TS
1334,53927,1,100551589,1,6,Bad Shercolor Match,16,IFC 8112NP,01DX8005513,,,77,10/23/2015,95816,,OV0020001,,MANUAL,10/21/2015,1,0,,1,MAN,,CUST,,CUSTOM MATCH,0,TRUE,TRUE,O,5394A0E67FFF4D01A0D9AD16FA29ABB1,POS.MISTINT.V0000.UP.Q,PROD_SMISC_BK,414D512050524F445F504F533133333464EB2956052C0020,10/23/2015 10:45,10/23/2015 10:45
2525,67087,1,650462328,1,4,Tinted Wrong Product,14,IFC 8012NP,Standalone-5,,,11,10/23/2015,104314,,A91W00353,,,10/20/2015,0.25,0,,0.25,,,COMP,,CUSTOM MATCH,0,TRUE,TRUE,O,1AC5D8742D47435EA05343D57372AD32,POS.MISTINT.V0000.UP.Q,PROD_SMISC_BK,414D512050524F445F504F533235323531C2295605350020,10/23/2015 10:46,10/23/2015 10:47
1350,163689,1,650462302,1,3,Tinted Wrong Color,14,IFC 8012NP,06DX8006805,,,1,10/23/2015,104907,,A91W00351,COLOR,6233,10/23/2015,0.25,0,,0.5,ENG,,SW,,PALETTE,0,TRUE,TRUE,O,F1A072BCC548412FA22052698B5B0C28,POS.MISTINT.V0000.UP.Q,PROD_SMISC_BK,414D512050524F445F504F53313335307BC12956053C0020,10/23/2015 10:52,10/23/2015 10:52

Надеюсь, что это не слишком запутанно, чтобы читать.

3 ответа

Data::Dumper выводит формат, который является допустимым perl и подходит для отладки, но не для записи файла CSV. Вы можете написать CSV вручную:

foreach my $row (@data) {
    print $OFG join(',', @$row), "\n";
}

но вам действительно следует использовать специализированный модуль, в данном случае Text:: CSV, как для чтения, так и для записи CSV - он будет обрабатывать все граничные случаи (например, поля со встроенными запятыми).

Синопсис содержит хороший пример как чтения, так и письма; Я не буду повторять это здесь.

Вам не нужно восстанавливать линию, если вы просто храните ее в @data тоже!

my @data;
while(my $line = <$FH>) {
    chomp($line);
    my @fields = split(/,/, $line);
    push @data, [ "$line\n", join('_', @fields[0..2]), @fields[19, 22, 25] ];
}

@data = sort {
    $a->[1] cmp $b->[1] ||
    $a->[2] cmp $b->[2] ||
    $a->[3] cmp $b->[3] ||
    $a->[4] cmp $b->[4]
} @data;

print($OFH $_->[0]) for @data;

Если ваши входные данные не содержат NUL, вы можете даже использовать следующий более быстрый подход:

print $OFH
   map { /[^\0]*\z/g }
   sort
   map {
      chomp;
      my @fields = split /,/;
      join("\0", join('_', @fields[0..2]), @fields[19, 22, 25], "$_\n")
   }
   <$FH>;

Но да, вы, вероятно, должны использовать законный парсер CSV.

use Text::CSV_XS qw( );

my $csv = Text::CSV_XS->new({ binary => 1, auto_diag => 1 });

my @data;
while (my $row = $csv->getline($FH)) {
    push @data, [ join('_', @$row[0..2]), $row ];
}

@data = sort {
    $a->[0]     cmp $b->[0]     ||
    $a->[1][19] cmp $b->[1][19] ||
    $a->[1][22] cmp $b->[1][22] ||
    $a->[1][25] cmp $b->[1][25]
} @data;

$csv->say($OFH, $_->[1]) for @data;

Ниже приведен быстрый подход с использованием синтаксического анализатора CSV:

use Text::CSV_XS qw( );

my $csv = Text::CSV_XS->new({ binary => 1, auto_diag => 2 });

print $OFH
   map { /[^\0]*\z/g }
   sort
   map {
      $csv->parse($_);
      my @fields = $csv->fields();
      join("\0", join('_', @fields[0..2]), @fields[19, 22, 25], $_)
   }
   <$FH>;

Не удалось использовать Text::CVS_XS, потому что он не был доступен на нашем сервере, к сожалению - но он нашел, что добавление этой единственной строки "print" сработало -

open my $OFH, '>', '/swpkg/shared/batch_processing/mistints/parsedTest.csv'; 
print $OFH join(',', @$_), $/ for @data; 
close $OFH; 

Протестировано нормально с небольшим файлом, теперь, чтобы проверить на реальном файле!

Другие вопросы по тегам