1

我是 Perl 的新手,恐怕我被卡住了,想问问是否有人可以帮助我。

我有一个包含旧名称和新名称两列(制表符分隔)的文件。

我想使用旧名称作为键,新名称作为值并将其存储为哈希。

然后我想打开一个不同的文件(gff 文件)并用新名称替换其中的所有旧名称并将其写入另一个文件。

我已经尽了最大的努力,但遇到了很多错误。

如果你能让我知道我做错了什么,我将不胜感激。

以下是这两个文件的外观:

旧名称新名称(SFXXXX)文件:

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

要在其中搜索和替换的文件(其中一行的示例):

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 循环中未定义,因为第一个 while 循环您在该范围内重新声明它们(即使您使用外部范围,它也会存储您处理的最后一个值,这不会有帮助) .

取出脚本顶部的my $oldnameand ,它是没用的。my $newname

取出整eva条 l 线。您需要为要替换的每件事重复正则表达式。尝试类似:

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

另见鲍罗丁的回答。他做了一个大的正则表达式而不是一个循环,并发现你缺少第二个参数来拆分。

于 2013-04-14T01:23:26.920 回答