【问题标题】:Perl data parsing and inserting linesPerl 数据解析和插入行
【发布时间】:2012-12-11 22:29:51
【问题描述】:

致全世界的 Perl 大师!

我有一个这样的文件要解析并想要制作......

从第一列开始,ID,外显子信息,起始位置,结束位置和方向。 ID遇到一个数就加1。

1   9239    712 8571    +
1   start_codon 712 714 +
1   stop_codon  8569    8571    +
2   3882    24137   24264   +
2   start_codon 24137   24139   +
3   3882    24322   24391   +
4   3882    24490   26064   +
4   stop_codon  26062   26064   +
5   4972    26704   26740   +
5   start_codon 26704   26706   +
6   4972    26814   27170   +
7   4972    27257   27978   +
7   stop_codon  27976   27978   +
8   10048   40161   41114   -
8   start_codon 41112   41114   -
8   stop_codon  40161   40163   -
9   272 43167   43629   -
9   stop_codon  43167   43169   -
10  272 43755   44059   -
10  start_codon 44057   44059   -

像这样......

1   9239    *712*   *8571*  +
1   start_codon 712 714 +
1   stop_codon  8569    8571    +
*X  9239    712 8571    +*
2   3882    *24137* 24264   +
2   start_codon 24137   24139   +
3   3882    24322   24391   +
4   3882    24490   *26064* +
4   stop_codon  26062   26064   +
*X  3882    24173   26064   +*
5   4972    *26704* 26740   +
5   start_codon 26704   26706   +
6   4972    26814   27170   +
7   4972    27257   *27978* +
7   stop_codon  27976   27978   +
*X  4972    26704   27978 +*
8   10048   *40161* *41114* -
8   start_codon 41112   41114   -
8   stop_codon  40161   40163   -
*X  10048   40161   41114   -*
9   272 *43167* 43629   -
9   stop_codon  43167   43169   -
10  272 43755   *44059* -
10  start_codon 44057   44059   -
*X  272 43167   44059   -*

必须添加以 X 开头的每一行,但以我的技能我不能... :(

问题是对于第二列中的每个外显子编号,忽略“start_codon”和“end_codon”,必须得到星号*之间的最小外显子位置和最大外显子位置。

这是我解析数据的基本代码......但我想,必须从头开始重新编码 (我不知道如何插入“X”行)

(对不起,我删除了代码,因为它不够好,可能会造成混乱......)

世界上的Perl大师,你能帮帮我吗???

谢谢!!

TLP 要求我放回我的代码。虽然代码很尴尬

use strict;

if (@ARGV != 1) {
    print "Invalid arguments\n";
    print "Usage: perl min_max.pl [exon_output_file]\n";
    exit(0);
}

my $FILENAME = $ARGV[0];
    my  $exonid = 0;
    my  $exon = "";
    my  $startpos = 0;
    my  $endpos = 0;
    my  $strand = "";
    my  $min_pos = 0;
    my  $max_pos = 0;

open (DATA, $FILENAME);

while (my $line = <DATA>) {
    chomp $line;

    if ($line ne "") {
        if ($line =~ /^(.+)\t(.+)\t(.+)\t(.+)\t(.+)/) {
        $exonid = $1;
        $exon = $2;
        $startpos = $3;
        $endpos = $4;
        $strand = $5;
        }
        if ($exon =~ /\d+/) {
            print $exonid,"\t",$exon,"\t",$startpos,"\t",$endpos,"\t",$strand,"\n";
        } else {
            print $exonid,"\t",$exon,"\t",$startpos,"\t",$endpos,"\t",$strand,"\n";
        }
    }
}

close (DATA);
exit;

如何比较最大值和最小值....

【问题讨论】:

  • 您没有尝试在任何地方存储最小值/最大值。这怎么可能行得通?
  • 没错,我正在尝试,但我做不到,所以我只是把最基本的代码从我删除了所有不起作用的部分开始。我还在努力。这就是为什么上面的代码如此简单。谢谢。 :(
  • 为什么*X 10048 40161 41114 -* 不是*X 10048 41112 41114 -* 在8 之后?
  • 忽略 start_codon 和 end_codon,我正在寻找每个编号的外显子信息的最小值和最大值。谢谢(第二列的数字是外显子信息。)
  • 你想让X成为什么?

标签: perl parsing


【解决方案1】:

基本上你所做的就是遍历这些行,跳过你不想要的那些(即第 2 列中没有数字),记住同一组中每个新行的最小/最大值,以及第 2 列数字何时发生变化您打印并重新开始。使用此解决方案,您还必须在最后手动打印最后一组。

此代码使用内部DATA 文件句柄来处理演示数据。只需将 &lt;DATA&gt; 更改为 &lt;&gt; 即可在目标输入文件上使用,如下所示:perl script.pl inputfile

use strict;
use warnings;
use List::Util qw(min max);

my $print;
my ($min, $max, $id);
while (<DATA>) {                   ###### change to <> to run on input file
    my @line = split;
    if ($line[1] !~ /^\d+$/) {                # if non-numbers in col 2
         print;                               # print line
         next;                                # skip to next line
    }
    if (!defined($id) or $id != $line[1]) {   # New dataset!
        say $print if $print;                 # Print and reset 
        $id = $line[1];
        $min = $max = undef;
    }
    $min = min($min // (), @line[2,3]);       # find min/max, skip undef
    $max = max($max // (), @line[2,3]);
    $print = join "\t", "X", $line[1], $min, $max;  # buffer the print
}
print $print;

__DATA__
1   9239    712 8571    +
1   start_codon 712 714 +
1   stop_codon  8569    8571    +
2   3882    24137   24264   +
2   start_codon 24137   24139   +
3   3882    24322   24391   +
4   3882    24490   26064   +
4   stop_codon  26062   26064   +
5   4972    26704   26740   +
5   start_codon 26704   26706   +
6   4972    26814   27170   +
7   4972    27257   27978   +
7   stop_codon  27976   27978   +
8   10048   40161   41114   -
8   start_codon 41112   41114   -
8   stop_codon  40161   40163   -
9   272 43167   43629   -
9   stop_codon  43167   43169   -
10  272 43755   44059   -
10  start_codon 44057   44059   -

输出:

9239    712     8571
3882    24137   26064
4972    26704   27978
10048   40161   41114
272     43167   44059

【讨论】:

  • 感谢 TLP 的帮助,但我想要的输出就像我问题中的第二个框。但是通读你的代码将帮助我更多地学习 perl。所以我很高兴并感谢您的帮助和时间。
  • @Karyo 这只是在next 语句之前添加print 语句,然后重新格式化$print 变量。除非您还想要最小/最大数字周围的 * 符号。
  • 感谢 TLP,你的工作更普遍!!!但是在下一条语句之前添加打印语句是什么意思?对不起,我不明白:(
  • 这不是火箭科学。我的意思是在单词next 之前添加单词print。 :) 我做了一些小的改动,你可以研究我的帖子的版本历史,看看我做了什么。点击显示edited X hours/minutes ago的部分。
【解决方案2】:

如果我对您的理解正确,这里有一种方法(未经测试!)可以满足您的要求:

use strict;
use warnings;
use feature 'say';

# read first line, initialize accumulators, print it back
chomp($_ = <>);
my ($last_id, $last_exon, $min_start, $max_end, $last_strand) = split /\t/;
say $_;

# loop over remaining lines
while (<>) {
    chomp;
    my ($exonid, $exon, $startpos, $endpos, $strand) = split /\t/;

    if ($exon !~ /\D/ and $exon != $last_exon) {
        # new exon found, print summary of last one...
        say join "\t", "X", $last_exon, $min_start, $max_end, $last_strand;
        # ...and reset accumulators
        ($last_id, $last_exon, $min_start, $max_end, $last_strand)
            = ($exonid, $exon, $startpos, $endpos, $strand);
    }
    else {
        # previous exon continues, just update accumulators
        $last_id     = $exonid;
        $last_exon   = $exon     if $exon !~ /\D/;
        $min_start   = $startpos if $min_start > $startpos;
        $max_end     = $endpos   if $max_end < $endpos;
        $last_strand = $strand;  # should not really be needed
    }
    # ...and don't forget to print the original line back again
    say $_;
}
# end of file, print summary of last exon
print join("\t", "X", $last_exon, $min_start, $max_end, $last_strand), "\n";

基本上,我假设您想要打印以X 开头的摘要行,只要您在第二列中遇到与该列中的前一个数字不同的数字,并且该行具有非数字值在第二列中永远不应该触发摘要。此外,您可能还希望在文件末尾添加一个摘要行。

如果$exon 仅包含数字,则表达式$exon !~ /\D/ 返回真。 (具体来说,它会测试它是否包含一个-数字字符,所以空字符串也会匹配。)

有很多边缘情况我没有考虑过,因为我不知道它们是否可能出现在您的数据中,以及如果确实发生了您希望如何处理它们。例如,为了小心,在外显子数保持不变的情况下,可能还希望打印一个摘要,以防链发生变化。同样,细心的程序员可能要考虑输入文件为空的可能性,或者第一行在第二列中包含非数字值的可能性。

至少在使用use warnings 时,如果我假设的任何值始终为数字,但结果并非如此,您将收到警报。

【讨论】:

  • 感谢 llmari Karonen!这段代码运行良好,但它没有打印出文件“1 9239 712 8571 +”的第一行并从第二行开始。但是thanx heaps我会设法做剩下的!
  • 我试过了,但这次第一行打印了两次。所以一旦我删除了'say $_;'从第一条 chomp 行开始,它就完美无缺!谢谢大家!
猜你喜欢
  • 2011-12-18
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多