【问题标题】:How can I modify fields in a CSV file with Perl?如何使用 Perl 修改 CSV 文件中的字段?
【发布时间】:2017-07-12 23:36:57
【问题描述】:

我有一个包含以下示例数据的 csv 文件。

o-option(alphabetical)
v-value(numerical)

number1,o1,v1,o2,v2,o3,v3,o4,v4,o5,v5,o6,v6
number2,o1,v11,o2,v22,o3,v33,o44,v44,o5,v55,o6,v66

and so on....

需要的输出。

NUM,o1,o2,o3,o4,o44,o5,o6
number1,v1,v2,v3,v4,,v5,v6
number2,v11,v22,v33,,v44,v55,v66

and so on...

在此数据中,文件中的所有选项都是相同的,即 o1、o2 等,但选项 4 的值正在变化,即 o4、o44 等。在 o4 字段中总共有大约 9 个不同的选项值。任何人都可以帮助我使用 perl 代码以获得所需的输出。

我已经编写了以下代码,但仍然没有得到所需的输出。

my @values;
my @options;
my %hash;

while (<STDIN>) {
chomp;
my ($srn,$o1,$v1,$o2,$v2,$o3,$v3,$o4,$v4,$o5,$v5,$o6,$v6) = split /[,\n]/, $_;
push @values, [$srn,$v1,$v2,$v3,$v4,$v5,$v6];
push @options, $o1,$o2,$o3,$o4,$o5,$o6;
}

#printing the header values
my @out = grep(!$hash{$_}++,@options);
print 'ID,', join(',', sort @out), "\n";

#printing the values.
for my $i ( 0 .. $#values) {
        print @{$values[$i]}, "\n";
}

输出:

ID,o1,o2,o3,o4,o44,o5,o6
number1,v1,v2,v3,v4,v5,v6
number2,v1,v2,v3,v44,v5,v6

从上面的输出来看,当值 44 出现时,它位于 option4 之下,因此其他值向左移动。这些值未与选项映射。请提出建议。

【问题讨论】:

  • 最好提供具体数据,而不仅仅是 o1,v1。输入实际的数字和内容。我无法通过此示例遵循您想要的内容。

标签: perl csv


【解决方案1】:

如果您想根据前面选项值的值将数值排列在列中,请将您的数据行存储为散列,使用选项作为散列的键。

use strict;
use warnings;

my (@data, %all_opts);

while (<DATA>) {
    chomp;
    my %h = ('NUM', split /,/, $_);
    push @data, \%h;
    @all_opts{keys %h} = 1;
}

my @header = sort keys %all_opts;
print join(",", @header), "\n";

for my $d (@data){
    my @vals = map { defined $d->{$_} ? $d->{$_} : '' } @header;
    print join(",", @vals), "\n";    
}


__DATA__
number1,o1,v1,o2,v2,o3,v3,o4,v4,o5,v5,o6,v6
number2,o1,v11,o2,v22,o3,v33,o44,v44,o5,v55,o6,v66

【讨论】:

    【解决方案2】:

    这就是你所追求的吗?

    use strict;
    use warnings;
    use 5.010;
    
    my %header;
    my @store;
    
    while (<DATA>) {
        chomp;
        my ($srn, %f) = split /,/;
        @header{ keys %f } = 1;
        push @store, [ $srn, { %f } ];
    }
    
    # header
    my @cols = sort keys %header;
    say join q{,} => 'NUM', @cols;
    
    # rows
    for my $row (@store) {
        say join q{,} => $row->[0], 
                         map { $row->[1]->{ $_ } || q{} } @cols;
    }
    
    __DATA__
    number1,o1,v1,o2,v2,o3,v3,o4,v4,o5,v5,o6,v6
    number2,o1,v11,o2,v22,o3,v33,o44,v44,o5,v55,o6,v66
    

    哪些输出:

    NUM,o1,o2,o3,o4,o44,o5,o6 
    number1,v1,v2,v3,v4,,v5,v6
    number2,v11,v22,v33,,v44,v55,v66
    

    【讨论】:

      【解决方案3】:

      通过文件识别所有不同的选项值,构建这些值的数组。

      第二次遍历文件:

      for each record
          initialise an associative array from your list of option value
          parse the assigning values for the options you have
          use your list of option values to iterate the associative array printing the values 
      

      【讨论】:

      • @Virus 文件有多大?有什么性能要求吗? (即实时进行)?
      • @Andrea:文件大小约为 70 到 80 mb。从文件中读取数据我没有遇到任何问题。
      【解决方案4】:

      您可能会查看 CPAN 模块 DBD::AnyData。那里最整洁的模块之一。它允许您像操作数据库一样操作 CSV 文件。还有更多。

      【讨论】:

        猜你喜欢
        • 2011-01-21
        • 2012-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-25
        • 2011-04-23
        • 2022-08-19
        • 2012-11-24
        相关资源
        最近更新 更多