如何按标题对CSV文件进行排序?

时间:2014-09-02 07:17:39

标签: perl sorting unix csv

有两个 CSV文件我想比较。但是,它们具有不同顺序的标头和行/值。

这是一个简单的例子:

INPUT FILE1:

NAME,AGE,BDAY
ABC,1,090214
DEF,1,122514

INPUT FILE2:

BDAY,NAME,AGE
122514,DEF,1
090214,ABC,1

INPUT FILE3:

BDAY,NAME,AGE
122514,DEFG,1
090214,ABC,1

Diff FILE1和FILE2

No diffs.

Diff FILE1和FILE3

Found diffs in FILE and FILE3.

<Any format of diffs is okay.>

我可以轻松地为此创建一个perl脚本,但在此之前,是否有人知道是否已有现有的脚本/工具?

我尝试将文件从UNIX复制到Windows,然后使用Excel对它们进行排序。它运作良好但我遇到了保存它的问题。

我也用谷歌搜索,但找不到这方面的参考。

感谢您的任何意见。

2 个答案:

答案 0 :(得分:2)

我认为您需要某种高级比较(需要更深入的分析),因此使用关系数据库方法可能很有趣。 在这方面,module DBD::CSV很有帮助。它允许写入SELECT语句,包括表之间的连接。

答案 1 :(得分:0)

规范化您的数据

  1. 使用Text::CSV重新排序CSV文件的列。
  2. 然后您可以使用Perl的sort或其他一些实用程序来重新排序文件行。
  3. 这也使用Text::Wrap以令人愉悦的格式显示规范化文件:

    use strict;
    use warnings;
    use autodie;
    
    # Setup fake data
    my @files;
    {
        local $/ = '';    # Paragraph mode
        while (<DATA>) {
            chomp;
            my ( $file, $data ) = split "\n", $_, 2;
            open my $fh, '>', $file;
            print $fh $data, "\n";
            push @files, $file;
        }
    }
    
    # Normalize Files by Column Order
    use Text::CSV;
    
    my $csv = Text::CSV->new( { binary => 1, eol => $/ } )
        or die "Cannot use CSV: " . Text::CSV->error_diag();
    
    for my $file (@files) {
        local @ARGV = $file;
        local $^I   = '.bak';
        my @old_order;
        my @new_order;
        while (<>) {
            if ( !$csv->parse($_) ) {
                die "Bad parse $file, line $.: " . $csv->error_diag();
            }
    
            my @columns = $csv->fields();
    
            if ( $. == 1 ) {
                @old_order = @columns;
                @new_order = sort @columns;
            }
    
            my %hash;
            @hash{@old_order} = @columns;
    
            if ( !$csv->combine( @hash{@new_order} ) ) {
                die "Bad combine $file, line $.: " . $csv->error_diag();
            }
    
            print $csv->string();
        }
        unlink "$file$^I";    # Optionally delete backup
    }
    
    # Normalize Files by Row Order
    for my $file (@files) {
        my ( $header, @data ) = do { local @ARGV = $file; <> };
        open my $fh, '>', $file;
        print $fh $header, sort @data;
    }
    
    # View Normalized Files
    use Text::Wrap;
    for my $file (@files) {
        open my $fh, '<', $file;
        print wrap( sprintf( "%-12s", $file ), ' ' x 12, <$fh>, ), "\n";
    }
    
    __DATA__
    file1.csv
    NAME,AGE,BDAY
    ABC,1,090214
    DEF,1,122514
    
    file2.csv
    BDAY,NAME,AGE
    122514,DEF,1
    090214,ABC,1
    
    file3.csv
    BDAY,NAME,AGE
    122514,DEFG,1
    090214,ABC,1
    

    输出:

    file1.csv   AGE,BDAY,NAME
                1,090214,ABC
                1,122514,DEF
    
    file2.csv   AGE,BDAY,NAME
                1,090214,ABC
                1,122514,DEF
    
    file3.csv   AGE,BDAY,NAME
                1,090214,ABC
                1,122514,DEFG