Perl:将值插入CSV文件

时间:2016-01-21 16:10:36

标签: arrays perl csv file-io

我有以下格式的CSV数据:

S.No,Label,Customer1,Customer2,Customer3...
1,label1,Y,N,Y
2,label2,N,Y,N
...

我需要重现"标签"到"客户"的标有 Y 的列 - 并且在标有 N 的列的左侧没有任何内容("")。

预期产出:

S.No,Label,Customer1,Customer1,Customer2,Customer2,Customer3,Customer3...
1,label1,label1,Y,"",N,label1,Y
2,label2,"",N,label2,Y,"",N

使用Excel打开时,它看起来像这样:

S.No   Label      Customer1   Customer1   Customer2   Customer2   Customer3   Customer3...
   1   label1      label1        Y                       N        label1          Y
   2   label2                    N         label2        Y                        N

两个最左边的列,指的是S.No和原始"标签"列,常量

最简单的方法是什么?我尝试了以下代码:

use strict;
use warnings;
my $nonIncludesFile = "nonIncludes.csv";
open(my $xfh, "+>", $nonIncludesFile) or warn "Unable to open $nonIncludesFile, $!";
chomp( my $header = <$xfh> );
my @names = split ",", $header;
my @names1;
my @fields;
my @fields1;
for(my $j=0; $j< scalar(@names); $j++)
{
    $names1[$j] = $names[$j];
}
while(<$xfh>)
{
    my $nonIncLine = $_;
    $nonIncLine = chomp($nonIncLine);
    @fields = split ",", $nonIncLine;
    next if $. == 1;                      #skip the first line

    for(my $i = 0; $i < scalar(@fields) -2; $i++)   #Number of "customers" = scalar(@fields) -2
    {
        $fields1[0] = $fields[0];
        $fields1[1] = $fields[1];
        if('Y' eq $fields[ $i + 2 ])
        {
            $fields1[$i+2] = 'Y';
            substr(@fields1, $i + 1, 0, $fields[1]);   #insert the label to the left - HERE
        }
        else
        {
            $fields1[$i+2] = 'N';
            substr(@fields1, $i + 1, 0, "");
        }
    }
}

print $xfh @names1;
print $xfh @fields1;

close($xfh);

但是这会引起&#34; substr在字符串之外&#34;在标有&#34; HERE&#34;。

的行

我做错了什么?有没有更简单(更好)的方法呢?

2 个答案:

答案 0 :(得分:2)

这样的事可能吗?

#!/usr/bin/perl

use strict;
use warnings;

#read the header row
chomp( my ( $sn, $label, @customers ) = split( /,/, <DATA> ) );
#double the 'customers' column headings (one is suffixed "_label")
print join( ",", $sn, $label, map { $_ . "_label", $_ } @customers ), "\n";

#iterate data
while (<DATA>) {
   #strip trailing linefeed
   chomp;
   #extract fields with split - note breaks if you've quoted commas inline. 
   my ( $sn, $label, @row ) = split /,/;
   print "$sn,$label,";
   #iterate Y/N values, and either prints "Y" + label, or anything else + blank. 
   foreach my $value (@row) {
      print join( ",", $value eq "Y" ? $label : "", $value ),",";
   }
   print "\n";
}


__DATA__
S.No,Label,Customer1,Customer2,Customer3
1,label1,Y,N,Y
2,label2,N,Y,N

假设您在字段中没有任何果味特殊字符(例如逗号),因为如果您这样做会中断,并且您可能想要考虑使用Text::CSV

答案 1 :(得分:1)

发布一些可用的测试数据总是比编写这样的问题

更好

但是,您的数据似乎没有引用字段或转义字符,因此看起来您只需使用splitjoin来处理CSV数据

这是一个满足您要求的Perl程序示例。示例输出按原样使用您的数据。必须向后处理每行数据,以便插入不会影响尚待处理的元素的索引

use strict;
use warnings 'all';
use feature 'say';

while ( <DATA> ) {

    chomp;
    my @fields = split /,/;

    for ( my $i = $#fields; $i > 1; --$i ) {

        my $newval = 
            $. == 1               ? $fields[$i] :
            lc $fields[$i] eq 'y' ? $fields[1] :
            '';

        splice @fields, $i, 0, $newval;
    }

    say join ',', @fields;
}

__DATA__
S.No,Label,Customer1,Customer2,Customer3...
1,label1,Y,N,Y
2,label2,N,Y,N

输出

S.No,Label,Customer1,Customer1,Customer2,Customer2,Customer3...,Customer3...
1,label1,label1,Y,,N,label1,Y
2,label2,,N,label2,Y,,N