根据列标题对CSV文件列值进行排序

时间:2019-08-02 10:19:11

标签: perl

嗨,我是新手fir perl脚本编写者,我需要一个帮助来实现用于对基于CSV文件标题的列值进行排序的逻辑。

示例:

S.NO,NAME,S2,S5,S3,S4,S1
1,aaaa,88,99,77,55,66
2,bbbb,66,77,88,99,55
3,cccc,55,44,77,88,66
4,dddd,77,55,66,88,99

现在我要按以下方式对该文件进行排序。

s.no,s2,s4,s5,s1,s0,name =>这就是我想要的,因为我定义了s.no,name,s1,s2,s3,s4,s5之类的标头顺序,它们分别是整个列的值也应该根据标题交换而改变,如何做到这一点……?

这是必需的输出,就像下面的波纹管一样

S.NO,NAME,S1,S2,S3,S4,S5 1,aaaaaaa,66,88,77,55,99 2,bbbbbbb,55,66,88,77,99 3,ccccccc,66,55,77,88,44 4,ddddddd,99,77,66,88,55

或我想要的列标题顺序,如下所示。

S.NO,NAME,S5,S4,S3,S2,S1->按照我的要求,我需要重新排序我的列标题,并且它也是相应的列值。

#!/usr/bin/perl


use strict;
use warnings;

use Text::CSV;
my $file = 'a1.csv';

my $size = 3;

my @files;

my $csv = Text::CSV->new ({ binary => 1, auto_diag => 1, sep_char => ';' });
open my $in, "<:encoding(utf8)", $file or die "$file: $!";
while (my $row = $csv->getline($in)) {
    if (not @files) {
        my $file_counter = int @$row / $size;
        $file_counter++ if @$row % $size;
        for my $i (1 .. $file_counter) {
            my $outfile = "output$i.csv";
            open my $out, ">:encoding(utf8)", $outfile or die "$outfile: $!";
            push @files, $out;
        }
    }

    my @fields = @$row;
    foreach my $i (0 .. $#files) {
        my $from = $i*$size;
        my $to   = $i*$size+$size-1;

        $to      = $to <= $#fields ? $to : $#fields;
        my @data = @fields[$from .. $to];

        $csv->print($files[$i], \@data);
        print {$files[$i]} "\n";
    }
}

3 个答案:

答案 0 :(得分:3)

#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use Text::CSV qw();
my @headers = qw(s.no name s1 s2 s3 s4 s5);
my $csv_in = Text::CSV->new({binary => 1, auto_diag => 1});
my $csv_out = Text::CSV->new({binary => 1, auto_diag => 1});
open my $in, '<:encoding(UTF-8)', 'a1.csv';
open my $out, '>:encoding(UTF-8)', 'output1.csv';
$csv_in->header($in);
$csv_out->say($out, [@headers]);
while (my $row = $csv_in->getline_hr($in)) {
    $csv_out->say($out, [$row->@{@headers}]);
}

答案 1 :(得分:2)

便捷的Text::AutoCSV模块使您可以将单列排列顺序重新排列:

$ perl -MText::AutoCSV -e 'Text::AutoCSV->new(in_file=>"in.csv",out_file=>"out.csv",out_fields=>["SNO","NAME","S1","S2","S3","S5"])->write()'
$ cat out.csv
s.no,name,s1,s2,s3,s5
1,aaaa,66,55,77,99
2,bbbb,55,99,88,77
3,cccc,66,88,77,44
4,dddd,99,88,66,55

我不确定您实际想要的字段顺序是什么,因为您有两个字段,并且两个字段都包含示例输入文件中没有的列(它有两个s2列;其中一个应该是s4吗?),但您应该明白这一点。列名必须全部使用大写字母,并带有特殊字符。删除,但实际名称用于输出。

答案 2 :(得分:0)

my $eix = "001"; $csv_in->header ($in, munge_column_names => sub { s/^$/"E".$eix++/er/; });