2017-05-19 4 views
4

私は、タブ区切りのテキストファイルをサブルーチンでネストされたハッシュに解析することを考えています。各ファイル行には、uid列の一意のIDと、ヘッダー行がネストされたキーとしてキーされます。どの列がuidの変更になるのですか(時には一意の列がないため、uidは列の組み合わせでなければなりません)。私の問題は、$uidという変数で補間されていない文字列として渡します。私はアイデアをしていますPerlのサブルーチン内で補間されていない渡された文字列を補間する

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"を渡すが、インスタンスのカップルに私はPerlのパーサの特徴である$uid$table{ACB1|123456}

答えて

3

補間を生産"$row{gene}|$row{rsid}"のを持っていると思いますができます。あなたは

"foo $bar baz" 

のようなものを書くとき、Perlはそれが実行時にデータを解釈することはありません

'foo ' . $bar . ' $baz' 

のようなものにそれをコンパイルします。あなたが持っているもの

は、文字の一つが$であることを起こるが、それは特別な効果を持っていない文字列です。


必要なものを行うには、少なくとも2つの方法があります。それらの1つは文字列ではなく関数を使用することです。 (どの補間が本当に実行時に連結を意味し、周りのコードを渡す方法は、関数内でそれをラップすることですので、理にかなっています。)

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, "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から対応する値ですべての単語を置き換えます。

my $lofrow = tablehash($lof_file, sub { my ($row) = @_; "$row->{gene}|$row->{rsid}" }, "transcript", "ENST"); 

別の解決策は、テンプレート文字列になるものを使用することです。


ランダムノート:

  • strictwarningsを使用するためのボーナスポイント。
  • if (!$colnum) { $colnum = 0; }$colnum ||= 0;に簡略化できます。
  • barewordファイルハンドルの代わりに字句変数を使用します。ベアワードは事実上グローバル変数です(そして、彼らが言語の一流の市民ではないので構文的に厄介です)。
  • 第2引数の予期しない解釈を避けるには、必ず3引数形式のopenを使用します。
  • プログラムの名前をエラーメッセージに含める(明示的に$0を指定するか、から\nを省略して暗黙指定する)。
  • my @foo =(); my %bar =();は冗長であり、my @foo; my %bar;に簡略化することができます。配列とハッシュは空になります。それらを空のリストで上書きするのは無意味です。
  • chomp(my $line = <INA>)は、undefを含む変数をchompしようとしているため、EOFに達したときに警告を表示します。
  • my %row;は、おそらくループ内で宣言する必要があります。それは、現在の行からの値だけを含んでいるように見えます。

提案:

open my $fh, '<', $file or die "$0: can't open $file: $!\n"; 
while (my $line = readline $fh) { 
    chomp $line; 
    ... 
} 
+0

おかげで、機能が完全に働きました。 chompのために、私は余分な改行を加えて警告を出させようとしましたが、字句ファイルハンドルの有無にかかわらず問題はないようです。それはちょうどバージョンの違い(私たちのサーバーはv5.10.1を実行している)であることですか? – dragon951

+0

@ dragon951されていないようです。私は5.8.9,5.10.1、5.24.1の警告を次のコードで表示します: 'perl -e '警告を使用します。 while(chomp(my $ line = <>)){} '/ dev/null' – melpomene