1

私は Perl を初めて使用し、行き詰まってしまったので、誰かが私を助けてくれるかどうか尋ねたかったのです。

oldname と newname の 2 つの列 (タブ区切り) を持つファイルがあります。

古い名前をキーとして、新しい名前を値として使用し、ハッシュとして保存したいと思います。

次に、別のファイル (gff ファイル) を開き、そこにあるすべての古い名前を新しい名前に置き換えて、別のファイルに書き込みたいと思います。

私は最善を尽くしましたが、多くのエラーが発生しています。

私が間違っていることを教えていただければ幸いです。

2 つのファイルの外観は次のとおりです。

oldname newname(SFXXXX) ファイル:

genemark-scaffold00013-abinit-gene-0.18 SF130001
augustus-scaffold00013-abinit-gene-1.24 SF130002
genemark-scaffold00013-abinit-gene-1.65 SF130003

検索して置換するファイル (行の 1 つの例):

scaffold00013   maker   gene    258253  258759  .   -   .   ID=maker-scaffold00013-augustus-gene-2.187;Name=maker-scaffold00013-augustus-gene-2.187;

これが私の試みです:

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

my $hashfile = $ARGV[0];
my $gfffile  = $ARGV[1];
my %names;
my $oldname;
my $newname;

if (!defined $hashfile) {
    die "Usage: $0 hash_file gff_file\n";
}

if (!defined $gfffile) {
    die "Usage: $0 hash_file gff_file\n";
}

###save hashfile with two columns, oldname and newname, into a hash with oldname as key and newname as value.

open(HFILE, $hashfile) or die "Cannot open $hashfile\n";

while (my $line = <HFILE>) {
    chomp($line);
    my ($oldname, $newname) = split /\t/;
    $names{$oldname} = $newname;
}

close HFILE;

###open gff file and replace all oldnames with newnames from %names.

open(GFILE, $gfffile) or die "Cannot open $gfffile\n";

while (my $line2 = <GFILE>) {
    chomp($line2);

    eval "$line2 =~ s/$oldname/$names{oldname}/g";

    open(OUT, ">SFrenamed.gff") or die "Cannot open SFrenamed.gff: $!";

    print OUT "$line2\n";

    close OUT;
}

close GFILE;

ありがとうございました!

4

2 に答える 2

3

あなたの主な問題は、$line変数を分割していないことです。split /\t/デフォルトで分割$_され、そこには何も入れていません。

このプログラムはハッシュを作成し、すべてのキーを長さの降順で並べ替え、|正規表現代替演算子で結合することにより、すべてのキーから正規表現を作成します。ソートは、選択肢がある場合にすべての可能な選択肢の中で最も長いものを選択するために必要です。

正規表現が出現するたびに、入力ファイルの各行で対応する新しい名前に置き換えられ、出力が新しいファイルに書き込まれます。

use strict;
use warnings;

die "Usage: $0 hash_file gff_file\n" if @ARGV < 2;

my ($hashfile, $gfffile) = @ARGV;

open(my $hfile, '<', $hashfile) or die "Cannot open $hashfile: $!";
my %names;
while (my $line = <$hfile>) {
    chomp($line);
    my ($oldname, $newname) = split /\t/, $line;
    $names{$oldname} = $newname;
}
close $hfile;

my $regex = join '|', sort { length $b <=> length $a } keys %names;
$regex = qr/$regex/;

open(my $gfile, '<', $gfffile) or die "Cannot open $gfffile: $!";
open(my $out, '>', 'SFrenamed.gff') or die "Cannot open SFrenamed.gff: $!";

while (my $line = <$gfile>) {
    chomp($line);
    $line =~ s/($regex)/$names{$1}/g;
    print $out $line, "\n";
}

close $out;
close $gfile;
于 2013-04-14T01:25:27.583 に答える
2

なぜ評価を使用しているのですか?そして$oldname、最初の while ループでそのスコープ内でそれらを再宣言するため、2 番目の while ループでは未定義になります (外側のスコープを使用した場合でも、処理した最後の値が格納されるため、役に立ちません)。 .

スクリプトの先頭にあるmy $oldnameandを削除すると、役に立ちません。my $newname

eval行全体を取り出します。置き換えたいものごとに正規表現を繰り返す必要があります。次のようなものを試してください:

$line2 =~ s/$_/$names{$_}/g for keys %names;

ボロディンの答えも参照してください。彼はループの代わりに 1 つの大きな正規表現を作成し、分割するための 2 番目の引数が不足していることに気付きました。

于 2013-04-14T01:23:26.920 に答える