【问题标题】:Different output from same code parsing simiiar tab-delimited files解析类似制表符分隔文件的相同代码的不同输出
【发布时间】:2017-05-01 13:09:45
【问题描述】:

下面的 Perl 脚本是用 shell 编写的。

如果我使用制表符分隔文件numeric,那么我会得到相应解析的每一行的所需结果。但是,如果我使用文件 alpha 作为输入,那么只会解析第一行。

alphanumeric 之间的唯一区别是 numericNC_000023

NC_000023.11:g.41747805_41747806delinsTT
NC_000023.11:g.41750615C>A

alphaNC_0000X

NC_0000X.11:g.41747805_41747806delinsTT
NC_0000X.11:g.41750615C>A

我错过了什么?

数字

Input Variant   Errors  Chromosomal Variant Coding Variant(s)
NM_003924.3:c.*18_*19delGCinsAA     NC_000023.11:g.41747805_41747806delinsTT    LRG_513t1:c.*18_*19delinsAA NM
NM_003924.3:c.013G>T        NC_000023.11:g.41750615C>A  LRG_513t1:c.13G>T   

阿尔法

Input Variant   Errors  Chromosomal Variant Coding Variant(s)
NM_003924.3:c.*18_*19delGCinsAA     NC_0000X.11:g.41747805_41747806delinsTT LRG_513t1:c.*18_*19delinsAA NM_003924.3:c.*18_*19delinsAA
NM_003924.3:c.013G>T        NC_0000X.11:g.41750615C>A   LRG_513t1:c.13G>T   NM_003924.3:c.13G>T

Perl

perl -ne '

next if $. == 1;

if ( /.*del([A-Z]+)ins([A-Z]+).*NC_0+([^.]+)\..*g\.([0-9]+)_([0-9]+)/ ) { # indel
    print join( "\t", $3, $4, $5, $1, $2 ), "\n";
}
else {

    while ( /\t*NC_(\d+)\.\S+g\.(\d+)(\S+)/g ) {

        # conditional parse

        ( $num1, $num2, $common ) = ( $1, $2, $3 );
        $num3 = $num2;

        if ( $common =~ /^([A-Z])>([A-Z])$/ ) {      # SNP
            ( $ch1, $ch2 ) = ( $1, $2 );
        }
        elsif ( $common =~ /^del([A-Z])$/ ) {        # deletion
            ( $ch1, $ch2 ) = ( $1, "-" );
        }
        elsif ( $common =~ /^ins([A-Z])$/ ) {        # insertion
            ( $ch1, $ch2 ) = ( "-", $1 );
        }
        elsif ( $common =~ /^_(\d+)del([A-Z]+)$/ ) { # multi deletion
            ( $num3, $ch1, $ch2 ) = ( $1, $2, "-" );
        }
        elsif ( $common =~ /^_(\d+)ins([A-Z]+)$/ ) { # multi insertion
            ( $num3, $ch1, $ch2 ) = ( "-", $1, $2 );
        }

        printf( "%d\t%d\t%d\t%s\t%s\n", $num1, $num2, $num3, $ch1, $ch2 ); # output

        map { undef } ( $num1, $num2, $num3, $common, $ch1, $ch2 );
    }
}' numeric

输出

23  41747805    41747806    GC  AA
23  41750615    41750615    C   A

使用 alpha 输出:

X   41747805    41747806    GC  AA

如果我在while 条件中使用\w 而不是\d,就像这样

while ( /\t*NC_(\w+)\.\S+g\.(\d+)(\S+)/g ) { ... }

我得到了这个结果

X   41747805    41747806    GC  AA
0   41750615    41750615    C   A

为什么$1 中的零

【问题讨论】:

  • 您在标题中提到制表符分隔,但您的文件中没有制表符。而且你没有对标签做任何事情。在 while (/\t* 旁边,这在那时是无用的,因为 \t 是否在输入中并不重要。
  • 您的代码布局非常糟糕,难以阅读。如果您想对自己这样做,我可以,但如果您向世界其他地方寻求免费帮助,那么努力并展示一些清晰的东西会更合适。您还必须在您编写的每个程序的顶部始终 use strictuse warnings 'all'。在您指望他人修复您的代码之前,它们将帮助您发现任何微不足道的错误。
  • @ULick:请写下您的第一条评论作为答案。
  • 看看perstyleperltidy。并且最好不要使用二十行“单行”;将代码放入文件中。
  • 您的第一个正则表达式会选择其中包含del.*ins(我简化了它)的行。我认为很可能,您在 else 部分找不到四个正则表达式之一。取决于你的真实输入。至少对于输入示例,这部分是无用的。

标签: perl shell


【解决方案1】:

while (/\t*NC_(\d+)\. 将不匹配“NC_0000X.11”,因为“X”并且正则表达式仅查找数字。

在您进行更改后,NC_(\w+) 将匹配“NC_0000X”并且$num1 设置为“0000X”。

您的printf "%d...." $num1 ... 将为非数字输入打印一个 0。因为$num1是'0000X',所以打印为0。

输入示例表明,每一行由字段组成,字段之间用空格分隔。有些领域是有趣的,有些则不是。每个字段都包含可识别的信息。

你的程序应该遵循这个结构。

  • 逐行读取文件
  • 将行拆分为字段
  • 跳过不感兴趣的字段,例如非 NC.*
  • 从字段中提取必要的信息
  • 做任何必要的事情,总结,收集它
  • 打印所需级别的信息。每个字段、行、文件或所有文件

使用较小的块而不是找到适用于整行的正则表达式要容易得多。它更易于阅读、理解和维护。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 2018-01-22
    • 2011-03-19
    相关资源
    最近更新 更多