【问题标题】:search and replace between two files -post#2在两个文件之间搜索和替换 -post#2
【发布时间】:2018-05-17 05:20:35
【问题描述】:

我需要用另一个文件中的信息/正则表达式替换一个文件中的变量。例如,我需要从 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";

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

File1 输出应如下所示:

    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

我当前的 perl 代码是:

use strict;
use warnings;
use vars qw($outfile @id $mstrg $gene);

open(SEARCH, $ARGV[0]) or die "Couldn't open $ARGV[0]: $!";
open(FILE, $ARGV[1]) or die "Couldn't open $ARGV[1]: $!";
$outfile = "testout.txt";
open (OUT, ">$outfile") || die "Can't open $outfile for creation: $!\n";

my %mstrg;

while (<SEARCH>) {
chomp;
if (/^MSTRG/) {
    chomp $_;
    @id = split (/\t/, $_);
        $mstrg{$id[1]}.="$id[1]";
 }
}
while (<FILE>) # {@ffn=<FILE>};
{
chomp ($gene=$_);
    if ($mstrg =~ /$gene/) {
    print OUT "$id[1]\t$id[2]";}
    else {
        #print OUT "$_\n";
            } 
next;
        }           

close FILE;

不幸的是,这就是我卡住的地方,不知道如何继续? 感谢您为之前的帖子提供的任何帮助、感谢和道歉,我没有向看到的人提供任何代码。

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    我会这样做有点像:

    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 cmets 后,上述内容可以简化为:

    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 });
    

    【讨论】:

    • 哇@jm666。收到错误Odd number of elements in hash assignment at ./test.pl line 12. (i.e. grep...) Can't locate object method "edit_lines" via package "Path::Tiny" at ./test.pl line 13.
    • 谢谢,我会花更多的精力看看我是否能弄清楚这个错误的原因。
    • 我认为我没有安装它 :)
    • 谢谢@jm666,我会努力解决这个问题,看看我能从哪里得到。
    • map { split /\s+/, s/.*?gene_id\s*"\s*(MSTRG\.\d+).*ref_gene_id\s*"\s*(Gene:\w+)".*/$1 $2/r } 一般写成map { /.*?gene_id\s*"\s*(MSTRG\.\d+).*ref_gene_id\s*"\s*(Gene:\w+)".*/ }。这样就不需要grep
    【解决方案2】:

    无需编写坚不可摧的代码即可达到您想要的结果

    此程序从包含MSTRG.Gene: 字符串的所有行中读取$file2 构建哈希%mstrg。然后它在$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
    

    【讨论】:

    • 谢谢@Borodin - 这显然是我级别的代码。我收到以下我不熟悉的错误 - 想知道您是否知道发生了什么,否则我会努力弄清楚。 'Can't open '' for reading: 'No such file or directory'` 指的是你的这行代码open my $fh, '&lt;', $file2; 我之前已经定义了 $files 所以...
    • @jnorth:就目前而言,它使用与您自己的代码相同的方案:file1file2 的路径是命令行参数。我猜你没有传递任何参数。
    • 天哪,我不觉得很傻吗 - 我在乱搞代码之后把它拿出来了,没想到把它放回去......再次感谢@Borodin!跨度>
    • @jnorth:除了复制我的代码并运行它之外,您不需要做任何其他事情。
    猜你喜欢
    • 2015-08-20
    • 2015-01-09
    • 2014-11-28
    • 1970-01-01
    • 2015-06-29
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    相关资源
    最近更新 更多