从txt文件perl中提取多个列

时间:2017-12-20 08:36:52

标签: arrays perl extract

我有一个这样的txt文件:

#Genera columnA columnB columnC columnD columnN
x1       1       3       7      0.9      2
x2       5       3       13     7        5
x3       0.1     0.8     7      1        0.4

我想提取X确定的列数,只是假设我们想要columnA,columnC和columnN(这可能是一个包含1,2,20,100或更多列的矩阵)和我要打印的内容OUT(这个例子只有3个但可能更多):

#Genera columnA columnC columnN
    x1   1       7       2
    x2   5       13      5
    x3   0.1     7       0.4

我试过了

#!/usr/bin/perl
use strict;
use warnings;


my @wanted_fields = qw/columnA columnC columnN/;

open DATA, '<', "columns.txt" or die "cant open file\n";


my @datain = <DATA>;
close DATA;

my (@unit_name, $names, @lines, @conteo, @match_names, @columnas);

foreach (@datain){
    if ($_=~ m/^$/g)            {   next;           }
    elsif ($_=~ m/#Genera/g)    {   $names= $_;     }
    else                        {   push @lines, $_ }
}


@unit_name = split (/\t/, $names);
shift @unit_name;
my $count =0;

    foreach (@wanted_fields){
        my $unit_wanted =$_;
        chomp $unit_wanted;
        foreach (@unit_name){
            if ($_ =~ m/$unit_wanted/g){
                $count++;
                 push (@conteo, $count);
                 push (@match_names, $_);
                }
        }
    }


    foreach (@lines){
        chomp;
        @columnas = split (/\t/, $_);
            #push @xx, $columnas[0][3];

    }

我使用count来确定要提取的列,但在这种情况下,数字2不对应于columnC而3则不对应于columnN ......这是一种选择任何给定列的简单方法,在这种情况下,我只想要3,但依赖于案例可能是1,2 5,10,100或更多列。

谢谢

3 个答案:

答案 0 :(得分:4)

您可以使用hash slices进行简化。

#!/usr/bin/env perl
use strict;
use warnings;

my @wanted = ( '#Genera' , qw (  columnA columnC columnN ));

open my $input, '<', "file.txt" or die $!;

chomp ( my @header = split ' ', <$input> ); 

print join "\t", @wanted, "\n";
while ( <$input> ) { 
   my %row;
   @row{@header} = split; 
   print join "\t", @row{@wanted}, "\n";
}

哪个输出:

#Genera columnA columnC columnN 
x1  1   7   2   
x2  5   13  5   
x3  0.1 7   0.4 

如果您想要完全匹配缩进,请将sprintf添加到混音中:

E.g:

print join "\t", map { sprintf "%8s", $_} @wanted, "\n";
while ( <$input> ) { 
   my %row;
   @row{@header} = split; 
   print join "\t", map { sprintf "%8s", $_} @row{@wanted}, "\n";
}

然后给出:

 #Genera     columnA     columnC     columnN           
      x1           1           7           2           
      x2           5          13           5           
      x3         0.1           7         0.4    

答案 1 :(得分:2)

这个程序就像你问的那样。它期望输入文件的路径作为命令行上的参数,然后可以使用空的&#34;菱形运算符&#34; <>没有明确打开它

文件的每个非空行都分为多个字段,标题行由第一个以哈希符号#

开头标识

map的调用将@wanted_fields数组转换为@fields的索引列表,其中列标题出现并将其存储在数组@idx

然后,此数组用于为每行输入切片@fields的所需列。字段打印,由制表符分隔

use strict;
use warnings 'all';

use List::Util 'first';

my @wanted_fields = qw/ columnA columnC columnN /;

my @idx;

while ( <> ) {
    next unless /\S/;

    my @fields = split;

    if ( $fields[0] =~ /^#/ ) {

        @idx = ( 0, map {
            my $wanted = $_;
            first { $fields[$_] eq $wanted } 0 .. $#fields;
        } @wanted_fields );
    }

    print join( "\t", @fields[@idx] ), "\n" if @idx;
}

输出

#Genera columnA columnC columnN
x1  1   7   2
x2  5   13  5
x3  0.1 7   0.4

答案 2 :(得分:2)

有用于此类应用程序的命令行开关:

perl -lnae 'print join "\t", @F[1,3,5]' file.txt

切换-a会自动为每一行创建变量@F,按空格分割。所以@F[1,3,5]是元素1,3和5的数组切片。

当然,缺点是您必须使用列号而不是名称。