1

我有一个大的 .csv 文件(2 - 300 万条记录)。我需要连接前三个字段(带下划线)并将其附加到每条记录,然后我需要根据该新字段和其他三个字段对文件进行排序。我能够做到这一点(目前正在使用 4 个记录文件对其进行测试) - 但我不确定如何以相同的 .csv 格式将其写回文件 - 而不是 Data::Dumper 格式化每个文件的方式行作为单独的变量。这是我到目前为止的代码 - 我有几行打印(到屏幕)行来看看它在做什么 -

#!/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

希望阅读起来不会太复杂。

4

3 回答 3

3

Data::Dumper输出一种有效的 perl 格式,适合调试,但不适合编写 CSV 文件。您可以手动编写 CSV:

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

但是您确实应该使用专门的模块,在本例中为Text::CSV,用于读取和写入 CSV - 它会处理所有边界情况(例如带有嵌入逗号的字段)。

概要包含阅读和写作的一个很好的例子;我不会在这里重复。

于 2016-03-28T17:29:34.570 回答
2

如果您也将其存储在其中,则不必重建生产线@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>;
于 2016-03-28T17:22:35.257 回答
0

无法使用 Text::CVS_XS 因为它在我们的服务器上不可用,不幸的是 - 但确实发现添加这个单一的“打印”行有效 -

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

用小文件测试很好,现在测试实际文件!

于 2016-03-28T18:45:38.903 回答