Perl替换不起作用

时间:2014-12-23 16:09:19

标签: regex string perl replace

我有以下代码:

use warnings;
use strict;

my %hash;

open TRADUCTOR, $ARGV[0];
open GTF, $ARGV[1];

while (my $line = <TRADUCTOR>) {
    chomp $line;
    my @chompline = split(/\t/, $line);
    $hash{$chompline[2]} = $chompline[1];
}

while (my $line = <GTF>) {
    my @chompline1 = split(/\t/, $line);
    my @chompline2 = split(/ /, $chompline1[8]);
    my @chompline3 = split(/;/, $chompline2[2]);
    my $transcript = $chompline3[0];
    $transcript =~ s/"//g;
    $transcript =~ s/PAC://g;
    my $transcript2 = $transcript;
    $transcript2 =~ s/(_[jox])/&&&$1/g;
    my @chompline4 = split(/&&&/, $transcript2);
    my $coletilla = $chompline4[1];
    my $transl = $hash{$chompline4[0]};
    if (defined $chompline4[1]) {
        $line =~ s/PAC:$transcript;/$transl.$coletilla;/ee;
    } else {
        $line =~ s/PAC:$transcript;/$hash{$chompline4[0]};/ee;
    }
    print $line;
}

第一个参数是以下文件(前十行):

Sb01g017490 Sb01g017490.1   1951419
Sb02g039360 Sb02g039360.1   1959410
Sb01g037620 Sb01g037620.1   1953645
Sb03g003880 Sb03g003880.1   1960464
Sb01g001330 Sb01g001330.1   1949441
Sb01g049890 Sb01g049890.1   1955138
Sb09g030646 Sb09g030646.1   1982110
Sb02g011950 Sb02g011950.1   1956744
Sb04g008540 Sb04g008540.1   1965938

第二个参数是以下文件(前十行):

A01 greenc1.0   exon    5409    5518    .   -   .   gene_id "Bra.XLOC_002074";transcript_id "Bra.TCONS_00002741";transcript_biotype "protein_coding"
A01 greenc1.0   exon    5616    5654    .   -   .   gene_id "Bra.XLOC_002074";transcript_id "Bra.TCONS_00002741";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8307    8530    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627_j.1";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8426    8530    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8599    8844    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627_j.1";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8599    8823    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8919    9056    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627_j.1";transcript_biotype "protein_coding"
A01 greenc1.0   exon    8919    9056    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627";transcript_biotype "protein_coding"
A01 greenc1.0   exon    9151    9413    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627_j.1";transcript_biotype "protein_coding"
A01 greenc1.0   exon    9151    9413    .   -   .   gene_id "Bra011902";transcript_id "PAC:22703627";transcript_biotype "protein_coding"

我想将文件2中的字符串替换为来自文件1的另一个字符串。但是,文本替换不起作用......没有替换任何内容。发生了什么事?

这是一段有问题的代码:

if (defined $chompline4[1]) {
    $line =~ s/PAC:$transcript;/$transl.$coletilla;/ee;
} else {
    $line =~ s/PAC:$transcript;/$hash{$chompline4[0]};/ee;
}

2 个答案:

答案 0 :(得分:3)

您在替换正则表达式上使用/ee。这是一种可怕的做法,只能用作Perl如何被滥用的令人沮丧的例子。或者鼓励熟练(?)程序员如何滥用Perl的例子。

您无需使用评估来插入变量。您不需要评估来连接字符串。你正在评估两次,这意味着:

$foo = "bar";   # assume
s/.../$foo/ee   # before
s/.../bar/e     # first eval
s/.../bar/      # second eval - bareword becomes string, if you are lucky

在第二个评估中发出的警告与您在程序中输入bar的警告相同:

Unquoted string "bar" may clash with future reserved word
Name "main::bar" used only once: possible typo

除非您希望数据被破坏,否则我建议您使用其他策略。您当前的代码允许部分匹配,删除分隔符,并且不考虑它应该在哪里引用。我假设这就是为了准备这个正则表达式替换而破坏你的数据的原因。

我会就如何解决问题给你一些建议,但我觉得我没有足够的有效信息来说明你要做什么,只是看起来你试图替换它。

"Bra011902";transcript_id "PAC:22703627";transcript_biotype "protein_coding"

Sb01g017490.1   

答案 1 :(得分:1)

我已经尝试过运行你的程序,但是很难,因为我不知道哪些空格是空格,哪些是标签。

我建议使用实际字段名称,而不是使用chomplines之类的随机名称。此外,使用/\s*/来破坏您的字段,这样您就可以同时获取标签和空格:

chomp $line; # You forgot it the first time around!
my ($f1, $f2, $f3, $f4, $f5, $f6...) = split /\s*/, $line;

其中$f1$f2等是被拆分字段的实际名称。

我个人会创建一个由字段值键入的哈希值:

my @fields = qw(field1 field2 field3 field4 field5 field6); 

然后,拆分该行并从中创建一个哈希值。 (我想用map)找出一种方法:

my %values;
my @field_values = split /\s+/, $line;
for my $index ( (0..$#fields) ) {
    $values{ $field[$index] } = $field_values[$index];
}

这将使您的程序更容易调试,更容易跟踪正在发生的事情。另外,通过使用/\s+/空白上拆分一次,您不必担心标签和空格混乱,或者两个标签分隔单个字段。您将需要第二次拆分以分割用分号分隔的字段,但使用字段名称而不是数组位置将使事情更容易使用。