English 中文(简体)
我该如何在 Perl 中从 CSV 文件中过滤特定列?
原标题:
  • 时间:2009-01-09 01:48:34
  •  标签:

I am just a beginner in Perl and need some help in filtering columns using a Perl script. I have about 10 columns separated by comma in a file and I need to keep 5 columns in that file and get rid of every other columns from that file. How do we achieve this?

谢谢任何人的帮助。

cheers, Neel

问题回答

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

它可以处理像含逗号的引用字段这样的情况,这是一个简单的拆分命令无法处理的。

CSV是一个不明确,复杂的格式(在引用、逗号和空格方面存在奇怪的问题)。寻找一个可以处理细微差别并且还可以通过列名进行索引的

当然,如果您只是想通过逗号拆分文本文件,那么不用再寻找,@Pax 的解决方案就足够了。

使用拆分将行分开,然后输出您想要的内容(例如每隔一个列),创建以下xx.pl文件:

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

然后执行:

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

如果您在谈论Windows中的CSV文件(例如,从Excel生成的文件),您需要注意处理包含逗号但被引号包括的字段。

在这种情况下,简单的分裂不起作用。

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

use Text::ParseWords;

将Pax上面的例子提到顶部,然后进行替换。

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

为了分开。

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

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

以上内容将使用逗号作为字段分隔符进行自动分割(-a),然后连接您感兴趣的字段并将其打印出来(包括换行符)。这假设数据是简单数据而不包含嵌套的逗号。我曾经使用不可打印的字段分隔符(x1d)进行这个操作,所以这对我来说不是问题。

请参见http://perldoc.perl.org/perlrun.html#Command-Switches以获取更多详细信息。

去查找了,没有找到一个好的能够符合CSV标准的灵活过滤程序,适用性也不仅仅是一次性的,于是我写了一个。欢迎使用。

基本用法是:

bash$ csvfilter [-r <columnTitle>]* [-quote] <csv.file> bash $ csvfilter [-r <columnTitle>]* [-quote] <csv.file>

#!/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
";
    }
}

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);

除了这里的人们所说的处理逗号分隔文件之外,我想指出可以使用数组切片和/或地图提取偶数(或奇数)数组元素:

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

希望它有帮助。

我的个人喜好是使用AnyData模块来做CSV处理。这个模块使事情变得非常简单,同时删除命名列也可以非常容易地完成。请在CPAN上查看





相关问题
热门标签