如何从Perl中的CSV文件中过滤掉特定列?

时间:2009-01-09 01:48:35

标签: perl csv

我只是Perl的初学者,在使用Perl脚本过滤列时需要一些帮助。 我在文件中有大约10个以逗号分隔的列,我需要在该文件中保留5列,并从该文件中删除所有其他列。我们如何实现这一目标?

非常感谢任何人的帮助。

欢呼声, 尼尔

10 个答案:

答案 0 :(得分:20)

查看Text::CSV(或Text::CSV_XS)来解析Perl中的CSV文件。它可以在CPAN上获得,或者如果您使用的是Linux或其他类Unix操作系统,则可以通过包管理器获取它。在Ubuntu中,包名为libtext-csv-perl。

它可以处理引用的字段之类的情况,因为它们包含逗号,这是简单的拆分命令无法处理的内容。

答案 1 :(得分:6)

CSV是一种定义不明确的复杂格式(引号,逗号和空格的奇怪问题)。寻找可以为您处理细微差别的a library,并为您提供方便,例如按列名索引。

当然,如果您只是想用逗号分割文本文件,那么请查看@ Pax的解决方案。

答案 2 :(得分:5)

使用split将线拉开,然后输出您想要的线(比如每隔一列),创建以下xx.pl文件:

while(<STDIN>) {
    chomp;
    @fields = split (",",$_);
    print "$fields[1],$fields[3],$fields[5],$fields[7],$fields[9]\n"
}

然后执行:

$ echo 1,2,3,4,5,6,7,8,9,10 | perl xx.pl
2,4,6,8,10

答案 3 :(得分:3)

如果您在谈论Windows中的CSV文件(例如,从Excel生成),则需要小心处理包含逗号本身但用引号括起来的字段。

在这种情况下,简单的拆分将无效。

答案 4 :(得分:2)

或者,您可以使用标准库中的Text::ParseWords。添加

use Text::ParseWords;

到上面Pax示例的顶部,然后替换

  my @fields = parse_line(q{,}, 0, $_);

分裂。

答案 5 :(得分:2)

您可以使用Perl的一些内置运行时选项在命令行上执行此操作:

$ echo "1,2,3,4,5" | perl -a -F, -n -e 'print join(q{,}, $F[0], $F[3]).qq{\n}' 1,4

以上将-a(utosplit)使用逗号的-F(字段)。然后它将加入您感兴趣的字段并将其打印出来(使用行分隔符)。这假设没有嵌套逗号的简单数据。我使用不可打印的字段分隔符(\ x1d)这样做,所以这对我来说不是问题。

有关详细信息,请参阅http://perldoc.perl.org/perlrun.html#Command-Switches

答案 6 :(得分:1)

看起来没有找到一个很好的符合csv标准的过滤器程序,它只是一个有用的灵活,所以我写了一个。享受。

基本用法是:

bash $ csvfilter [-r&lt; columnTitle&gt;] * [-quote]&lt; csv.file&gt;

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;

use Text::CSV;

my $always_quote=0;

my @remove;
if ( ! GetOptions('remove:s'=> \@remove,
          'quote-always'=>sub {$always_quote=1;}) ) {
   die "$0:invalid option (use --remove  [--quote-always])";
}

my @cols2remove;

sub filter(@)
{
   my @fields=@_;
   my @r;
   my $i=0;
   for my $c (@cols2remove) {
       my $p;
       #if ( $i  $i ) {
       push(@r, splice(@fields, $i));
   }
   return @r;
}

# create just one if these
my $csvOut=new Text::CSV({always_quote=>$always_quote});

sub printLine(@)
{
    my @fields=@_;
    my $combined=$csvOut->combine(filter(@fields));
    my $str=$csvOut->string();
    if ( length($str) ) {
     print "$str\n";
    }
}

my $csv = Text::CSV->new();

my $od;
open($od, "| cat") || die "output:$!";
while () {
    $csv->parse($_);
    if ( $. == 1 ) {
    my $failures=0;
    my @cols=$csv->fields;
    for my $rm (@remove) {
        for (my $c=0; $c$b} @cols2remove);
    }
    printLine($csv->fields);
}

exit(0);
\

答案 7 :(得分:0)

除了人们在这里谈到处理逗号分隔文件的内容之外,我还要注意,可以使用数组切片和/或映射提取偶数(或奇数)数组元素:

@myarray[map { $_ * 2 } (0 .. 4)]

希望它有所帮助。

答案 8 :(得分:0)

我个人最喜欢的CSV方式是使用AnyData module。它似乎使事情变得非常简单,并且可以相当容易地删除命名列。 Take a look on CPAN

答案 9 :(得分:-3)

这回答了一个更大的问题,但似乎是一个很好的相关信息。

unix cut命令可以做你想要的(还有更多)。它一直是reimplemented in Perl