我希望使用子例程将制表符分隔的文本文件解析为嵌套哈希。每个文件行将由来自uid列的唯一ID键控,标题行作为嵌套键。哪个(哪些)列成为uid更改(因为有时没有唯一的列,因此uid必须是列的组合)。我的问题是$uid
变量,我将其作为非插值字符串传递。当我尝试以插值的方式在子程序中使用它时,它只会给我非插值的值:
use strict;
use warnings;
my $lofrow = tablehash($lof_file, '$row{gene}', "transcript", "ENST");
##sub to generate table hash from file w/ headers
##input values are file, uid, header starter, row starter, max column number
##returns hash reference (deref it)
sub tablehash {
my ($file, $uid, $headstart, $rowstart, $colnum) = @_;
if (!$colnum){ # takes care of a unknown number of columns
$colnum = 0;
}
open(INA, $file) or die "failed to open $file, $!\n";
my %table; # permanent hash table
my %row; # hash of column values for each row
my @names = (); # column headers
my @values = (); # line/row values
while (chomp(my $line = <INA>)){ # reading lines for lof info
if ($line =~ /^$headstart/){
@names = split(/\t/, $line, $colnum);
} elsif ($line =~ /^$rowstart/){ # splitting lof info columns into variables
@values = split(/\t/, $line, $colnum);
@row{@names} = @values;
print qq($uid\t$row{gene}\n); # problem: prints "$row{gene} ACB1"
$table{"$uid"} = { %row }; # puts row hash into permanent hash, but with $row{gene} key)
}
}
close INA;
return \%table;
}
我没有想法。我可以放$table{$row{$uid}}
并简单地传递"gene"
,但在一些情况下,我希望$uid
"$row{gene}|$row{rsid}"
生成$table{ACB1|123456}
答案 0 :(得分:3)
插值是Perl 解析器的一个功能。当你写像
这样的东西"foo $bar baz"
,Perl将其编译为类似
的内容'foo ' . $bar . ' $baz'
它不会在运行时解释数据。
你所拥有的是一个字符串,其中一个字符恰好是$
但没有特殊效果。
至少有两种方法可以做你想要的事情。其中之一是使用函数,而不是字符串。 (这是有道理的,因为插值实际上意味着在运行时连接,并且传递代码的方法是将其包装在函数中。)
my $lofrow = tablehash($lof_file, sub { my ($row) = @_; $row->{gene} }, "transcript", "ENST");
sub tablehash {
my ($file, $mkuid, $headstart, $rowstart, $colnum) = @_;
...
my $uid = $mkuid->(\%row);
$table{$uid} = { %row };
这里$mkuid
不是字符串,而是对函数的引用(给定哈希引用)返回一个uid字符串。 tablehash
调用它,将%row
的引用传递给它。然后您可以将其更改为例如。
my $lofrow = tablehash($lof_file, sub { my ($row) = @_; "$row->{gene}|$row->{rsid}" }, "transcript", "ENST");
另一种解决方案是使用相当于模板字符串的内容:
my $lofrow = tablehash($lof_file, "gene|rsid", "transcript", "ENST");
sub tablehash {
my ($file, $uid_template, $headstart, $rowstart, $colnum) = @_;
...
(my $uid = $uid_template) =~ s/(\w+)/$row{$1}/g;
$table{$uid} = { %row };
s///
代码遍历模板字符串,并使用%row
中的相应值手动替换每个单词。
随机笔记:
strict
和warnings
的加分点。if (!$colnum) { $colnum = 0; }
可简化为$colnum ||= 0;
。$0
或隐式地忽略\n
中的die
)。my @foo = (); my %bar = ();
是多余的,可以简化为my @foo; my %bar;
。数组和哈希开始是空的;用空列表覆盖它们是没有意义的。chomp(my $line = <INA>)
会发出警告(因为你正试图扼杀包含undef
的变量。)my %row;
应该在循环中声明。看起来它应该只包含当前行的值。建议:
open my $fh, '<', $file or die "$0: can't open $file: $!\n";
while (my $line = readline $fh) {
chomp $line;
...
}