我有一个这样的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或更多列。
谢谢
答案 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的数组切片。
当然,缺点是您必须使用列号而不是名称。