搜索并替换两个文件-post#2

时间:2017-12-03 18:12:06

标签: regex perl

我需要用另一个文件中的信息/正则表达式替换一个文件中的变量。例如,我需要从file1中的每一行获取第一个字符串/变量(以MSTRG开头):

MSTRG.5734  MSTRG.5734  509 -4  0   -14 0   0
MSTRG.19266 MSTRG.19266 842 -4  0   -12 0   0
MSTRG.26588 MSTRG.26588 196 5   0   12  0   0

并使用它在file2中搜索看起来像这样的内容:

Chr1    StringTie   transcript  24039360    24041181    1000    -   .   gene_id "MSTRG.5734"; transcript_id "MSTRG.5734.1"; 
Chr1    StringTie   transcript  24039810    24040595    1000    -   .   gene_id "MSTRG.5734"; transcript_id "Transcript:AT1G64700.1"; ref_gene_id "Gene:AT1G64700"
Chr1    StringTie   exon    24040560    24041181    1000    -   .   gene_id "MSTRG.19266"; transcript_id "MSTRG.19266.1"; exon_number "2"; 
Chr1    StringTie   exon    24040560    24041181    1000    -   .   gene_id "MSTRG.26588"; transcript_id "MSTRG.26588.1"; exon_number "2"; 
Chr1    StringTie   transcript  24039810    24040595    1000    -   .   gene_id "MSTRG.26588"; transcript_id "Transcript:AT5G41000.1"; ref_gene_id "Gene:AT5G41000";

理想情况下,例如{2}在file2中的一行中找到,该行也包含字符串,例如MSTRG.5734,它会获取信息Gene:AT1G64700并替换file1中的Gene:AT1G64700。因此,file1中每行的每个MSTRG.5734都是唯一的,理论上它与file2中的唯一Gene匹配。如果它与Gene不匹配,那么我需要维护file1中的原始行。

File1输出应该如下所示:

MSTRG

我目前的perl代码是:

    Gene:AT1G64700  MSTRG.5734  509 -4  0   -14 0   0
    MSTRG.19266 MSTRG.19266 842 -4  0   -12 0   0
    Gene:AT5G41000  MSTRG.26588 196 5   0   12  0   0

不幸的是,我遇到了困难,不确定如何继续? 感谢上一篇文章给出的任何帮助,赞赏和道歉,我没有为那些看到的人提供任何代码。

2 个答案:

答案 0 :(得分:3)

我会这样做:

use 5.014;               #needed min 5.014 because the /r modifier
use warnings;
use Path::Tiny '0.077';  #added the min. req. version

my $file1='file1.txt';
my $file2='file2.txt';

my %mstmap = map { split /\s+/, s/.*?gene_id\s*"\s*(MSTRG\.\d+).*ref_gene_id\s*"\s*(Gene:\w+)".*/$1 $2/r }
             grep { /ref_gene_id.*Gene:/ } path($file2)->lines({chomp => 1});
path($file1)->edit_lines( sub { s/^(MSTRG\.\d+)/exists($mstmap{$1}) ? $mstmap{$1} : $1/e });
输入文件的

生成

Gene:AT1G64700  MSTRG.5734  509 -4  0   -14 0   0
MSTRG.19266 MSTRG.19266 842 -4  0   -12 0   0
Gene:AT5G41000 MSTRG.26588 196 5   0   12  0   0

它为对创建哈希:MSTRG.number => Gene:String(来自file2),并使用Path::Tiny模块编辑功能执行file1中的替换。

在@Borodin评论之后,上述内容可以简化为:

use 5.014;
use warnings;
use Path::Tiny '0.077';

my $file1='f1';
my $file2='f2';

my %mstmap = map {
    /.*?gene_id\s*"\s*(MSTRG\.\d+).*ref_gene_id\s*"\s*(Gene:\w+).*/
} path($file2)->lines({chomp => 1});
path($file1)->edit_lines( sub { s/^(MSTRG\.\d+)/exists($mstmap{$1}) ? $mstmap{$1} : $1/e });

答案 1 :(得分:2)

没有必要编写坚不可摧的代码来实现您想要的结果

此程序从包含$file2%mstrg字符串的所有行中读取MSTRG.构建哈希Gene:。然后它会在$re中创建一个匹配找到MSTR.字符串中的任何一个的正则表达式

$file1被打开,并且该正则表达式用于替换任何散列键以及它在行首处出现的相应散列值。然后打印该行

目前尚不清楚file1.txt的前两个字段是否始终相同,但我选择仅更改第一个字段

我已经使用autodie pragma来避免显式检查任何文件IO操作是否成功

程序将输出打印到STDOUT,因此您可以在命令行的任何位置将其重定向

use strict;
use warnings 'all';
use autodie;

my ( $file1, $file2 ) = @ARGV;

my %mstrg;

{
    open my $fh, '<', $file2;

    while ( <$fh> ) {
        $mstrg{$1} = $2 if /"(MSTRG.\d+)".*"(Gene:\w+)"/;
    }
}

my $re = join '|', sort { length $b <=> length $a } keys %mstrg;

open my $fh, '<', $file1;

while ( <$fh> ) {
    s/^($re)\b/$mstrg{$1}/;
    print;  
}

输出

Gene:AT1G64700  MSTRG.5734  509 -4  0   -14 0   0
MSTRG.19266 MSTRG.19266 842 -4  0   -12 0   0
Gene:AT5G41000 MSTRG.26588 196 5   0   12  0   0