我有类似Stack Overflow post Substituting array elements from one tab delimited file with hash values from another file using Perl 的情况。我试图用特定列中各自的值替换匹配哈希键的字符串。
Given the @array:
a b abbd
cc d abcd
gg hh cdag
and the %hash:
$VAR1 = {
'a' => 'GAT_1',
'b' => 'GAT_2',
'cc' => 'GAT_3',
'd' => 'GAT_4',
'gg' => 'GAT_5',
'hh' => 'GAT_6',
};
我已经尝试过这段代码,但它不起作用。如何限制仅替换匹配键的前两个实例(列)? (也就是说,保持第三列不变?)
foreach $line (@array) {
my @cols = split (/\s+/, $line);
$cols[0] = $hash{cols[0]};
$cols[1] = $hash{cols[1]};
push @newarray, $line;
}
Expected output:
GAT_1 GAT_2 abbd
GAT_3 GAT_4 abcd
GAT_5 GAT_6 cdag
答案 0 :(得分:1)
只需在替换后加入列:
my $line_after_lookup;
foreach $line (@array) {
my @cols = split (/\s+/, $line);
if (defined($$VAR1{$cols[0]})) { $cols[0] = $$VAR1{$cols[0]}; }
if (defined($$VAR1{$cols[1]})) { $cols[1] = $$VAR1{$cols[1]}; }
#
# When using a hash instead of a hash reference, replace the previous 2 statements with the following 2 lines:
# if (defined($hash{$cols[0]})) { $cols[0] = $hash{$cols[0]}; }
# if (defined($hash{$cols[1]})) { $cols[1] = $hash{$cols[1]}; }
#
$line_after_lookup = join ( ' ', @cols );
push @newarray, $line_after_lookup ;
}
答案 1 :(得分:0)
这就是诀窍:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my %substitute = (
'a' => 'GAT_1',
'b' => 'GAT_2',
'cc' => 'GAT_3',
'd' => 'GAT_4',
'gg' => 'GAT_5',
'hh' => 'GAT_6',
);
my @newarray;
while (<DATA>) {
my @fields = split;
$fields[0] = $substitute{ $fields[0] };
$fields[1] = $substitute{ $fields[1] };
push ( @newarray, join( " ", @fields ));
}
print Dumper \@newarray;
__DATA__
a b abbd
cc d abcd
gg hh cdag
打印:
$VAR1 = [
'GAT_1 GAT_2 abbd',
'GAT_3 GAT_4 abcd',
'GAT_5 GAT_6 cdag'
];
您的工作无效,因为您正在更改@fields
而不是$line
的内容。然而另一个可能的问题是你的分裂 - split /\s+/
处理领先的空格不同(你得到一个空字段)。
答案 2 :(得分:0)
如何限制只替换匹配键的前两个实例(列)? (即保持第三列不变?)
一种方法是使用正则表达式,只选择那两列并执行适当的替换。
插图(已编辑):
#!/usr/bin/perl
my @array = (
"a b abbd",
"cc d abcd",
"gg hh cdag",
"ii jj kmln" # to show what happens when no mapping exists
);
my %hash = (
'a' => 'GAT_1',
'b' => 'GAT_2',
'cc' => 'GAT_3',
'd' => 'GAT_4',
'gg' => 'GAT_5',
'hh' => 'GAT_6',
);
sub replace { $hash{$_[0]} || $_[0]; } # original string if no mapped value
sub convert { replace($_[0]) . $_[1] . replace($_[2]); }
my @newarray = map
{
my $line = $_;
$line =~ s/(\w+)(\W+)(\w+)/convert($1, $2, $3)/e;
$line;
} @array;
print "$_\n" for @newarray;
此处需要替换:
$line =~ s/(\w+)(\W+)(\w+)/convert($1, $2, $3)/e;
e
表达式上的s///
修饰符会导致第二部分中的替换表达式被计算,从而调用sub convert()。 convert()的参数来自第一部分正则表达式中的捕获:(\w+)
捕获第一个单词字符序列,(\W+)
捕获非单词字符,如空格或标点符号,再次(\w+)
捕获第二个单词字符序列。线路的其余部分无关紧要,根本不需要解析,保持不变。
如果映射值不可用,您可能还需要考虑会发生什么。在这种情况下,上面的代码保留原始字符串。