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;
Протестировано нормально с небольшим файлом, теперь, чтобы проверить на реальном файле!