【问题标题】:Perl script (or anything) to total up CSV columnPerl 脚本(或任何东西)总计 CSV 列
【发布时间】:2011-05-08 18:20:52
【问题描述】:

我(在其他人的帮助下)写了一个awk command 来汇总 CSV 文件中的一列。不幸的是,我在谷歌搜索后得知awk 不擅长处理 CSV 文件,因为分隔符并不总是相同的(即用引号括起来时应该忽略逗号)。

似乎 Perl 脚本可以做得更好。是否有可能有一个单行 Perl 脚本(或几乎一样简洁的东西)来实现与此 awk 命令相同的功能,该命令总计 CSV 文件的第 5 列?

cat file.csv | awk -F "\"*,\"*" '{s+=$5} END {printf("%01.2f\n", s)}'

我并没有特别喜欢 Perl,但我希望避免编写成熟的 PHP 脚本。到这个时候,我本可以轻松编写一个 PHP 脚本,但是现在我已经走到了这一步,我想看看我是否可以完成它。

【问题讨论】:

    标签: perl csv awk


    【解决方案1】:

    您需要使用体面的 CSV 解析器来处理 CSV 格式的所有复杂性。 Text::CSV_XS(或Text::CSV,如果不可用)是首选之一。

    perl -e '{use Text::CSV_XS; my $csv=Text::CSV_XS->new(); open my $fh, "<", "file.csv" or die "file.csv: $!"; my $sum = 0; while (my $row = $csv->getline ($fh)) {$sum += $row->[4]}; close $fh; print "$sum\n";}'
    

    这是实际的 Perl 代码,以提高可读性

    use Text::CSV_XS; # use the parser library
    my $csv = Text::CSV_XS->new(); # Create parser object
    open my $fh, "<", "file.csv" or die "file.csv: $!"; # Open the file. 
    my $sum = 0; 
    while (my $row = $csv->getline ($fh)) { # $row is array of field values now
        $sum += $row->[4];
    }
    close $fh; 
    print "$sum\n";
    

    可以通过使用质量稍差但更密集的 Perl 来缩短上述内容

    cat file.csv | perl -MText::CSV_XS -nae '$csv=Text::CSV_XS->new(); 
                   $csv->parse($_); @f=$csv->fields(); $s+=$f[4]} { print "$s\n"'
    

    【讨论】:

    • 我不知道 Perl,但 } { 在您的密集版本中看起来很奇怪。 -n 循环中是否有隐含的 {} 您不必提供?
    • 您的带有cat 的版本不适用于包含多行字符串字段的 CSV 文件。
    • @Dennis - } { fooEND{ foo } 的缩写形式
    【解决方案2】:

    您反对使用 Perl 模块吗?您可以使用Text::CSV 轻松完成此操作,而无需滚动您自己的解析器。

    Tutorialsn-p 改为执行总:

    # ... some tutorial code ommited
    while (<CSV>) {
        if ($csv->parse($_)) {
            my @columns = $csv->fields();
            $total += $columns[4];
        } else {
            my $err = $csv->error_input;
            print "Failed to parse line: $err";
        }
    }
    print "total: $total\n";
    

    【讨论】:

      【解决方案3】:

      Python

      import csv
      with open( "some_file.csv", "rb" ) as source:
          rdr= csv.reader( source )
          col_5= 0
          for row in rdr:
              col_5 += row[5]
      print col_5
      

      不是单行字,而是相当简洁。

      【讨论】:

        【解决方案4】:

        有很多工具可以做到这一点。快速搜索“cli csvparser”后,我找到了几个工具(我显然无法链接到这些工具——可能是为了防止垃圾邮件)。

        我安装了我找到的第一个工具——csvtool——并且能够执行与您的命令行类似的命令行并获得总数。

        【讨论】:

          【解决方案5】:

          非常短(且快速)的解决方案:

          perl -MText::CSV_XS -E'$c=new Text::CSV_XS;$s+=$r->[4]while$r=$c->getline(*ARGV);say$s' file.csv
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-10-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多