Perl 如何以适当的方式使用until函数

Perl 如何以适当的方式使用until函数,perl,Perl,我有一个要筛选的文件,如下所示: ##matrix=axtChain 16 91,-114,-31,-123,-114,100,-125,-31,-31,-125,100,-114,-123,-31,-114,91 ##gapPenalties=axtChain O=400 E=30 chain 21455232 chr20 14302601 + 37457 14119338 chr22 14786829 + 3573 14759345 1 189 159 123 24

我有一个要筛选的文件,如下所示:

##matrix=axtChain 16 91,-114,-31,-123,-114,100,-125,-31,-31,-125,100,-114,-123,-31,-114,91
##gapPenalties=axtChain O=400 E=30
chain 21455232 chr20 14302601 + 37457 14119338 chr22 14786829 + 3573 14759345 1
189     159     123
24      30      22
165     21      20
231     105     0
171     17      19
261     0       2231
222     2       0
253     56      48

chain 164224 chr20 14302601 + 1105938 1125118 chr22 14786829 + 1081744 1100586 8
221     352     334
24      100     112
34      56      56
26      50      47
…………………….
chain 143824 chr20 14302601 + 1105938 1125118 chr22 14786829 + 1081744 1100586 8
因此,简单地说,有一些块由一个空行分隔。 每个块以行“chain xxxxx”开始,并以带数字的行继续。 我想过滤掉文件,只保留带有链的块,后面的数字大于3000。 为此,我编写了以下脚本:

#!/usr/bin/perl
use strict;
use warnings;
use POSIX;

my $chain = $ARGV[0];

#It filters the chains with chains >= 3000.
open my $chain_file, $chain or die "Could not open $chain: $!";

my @array;
while( my $cline = <$chain_file>)  {
    #next if /^\s*#/;
    chomp $cline;
    #my @lines = split (/ /, $cline);
    if ($cline =~/^chain/) {
        my @lines = split (/\s/, $cline);
        if ($lines[1] >= 3000) {
            #print $lines[1];
            #my @lines = split (/ /, $cline);

            #print "$cline\n";
            push (@array, $cline);
        }
    }
    until ($cline ne ' ') {
        push (@array, $cline);
    }


    foreach (@array) {
        print "$_\n";

    }
    undef(@array);
}
#/usr/bin/perl
严格使用;
使用警告;
使用POSIX;
my$chain=$ARGV[0];
#它过滤链>=3000的链。
打开我的$chain_文件,$chain或die“无法打开$chain:$!”;
我的@数组;
而(我的$cline=){
#下一个if/^\s*#/;
咀嚼$cline;
#my@lines=拆分(/,$cline);
如果($cline=~/^chain/){
my@lines=拆分(/\s/,$cline);
如果($line[1]>=3000){
#打印$行[1];
#my@lines=拆分(/,$cline);
#打印“$cline\n”;
推送(@array,$cline);
}
}
直到($cline ne''){
推送(@array,$cline);
}
foreach(@array){
打印“$\u\n”;
}
未定义(@array);
}
问题是我只能打印标题(链XXXXX…),而不能打印每个块下一行的数字。 我正在使用“直到”函数直到找到空白行,但它不起作用。 如果有人能帮我…。 事先非常感谢,
Vasilis.

这里的第一个问题是
'
是一个空格,而不是一个空行(
'
'
应该可以,因为您已经
选择了该行

第二个问题是

until ( $cline ne "" )

while ( $cline eq "" )
这与将行推送到
@array
所需的相反

也就是说,触发器运算符可能更适合您所追求的内容:

my @array;
while ( <$chain_file> ) {          # Using $_ instead of $cline

    chomp;

    if ( do { /^chain\s+(\d+)/ && $1 >= 3000 } .. /^$/ ) {

                                   # Accumulate lines in @array
        push @array, $_;           # False until LHS evaluates to true ...
    }                              # ... then true until RHS evaluates to true

    else {
        for ( @array ) {
          print $_, "\n";          # Print matches
        }
        @array = ();               # Reset/clear out @array
    }
}
my@array;
而(){#使用$而不是$cline
咀嚼;
如果(do{/^chain\s+(\d+/&&&$1>=3000}../^$/){
#在@array中累加行
推送@array,$\u;#False,直到LHS的计算结果为true。。。
}#…然后为真,直到RHS计算为真
否则{
for(@array){
打印$\“\n”\ \打印匹配项
}
@数组=();#重置/清除@数组
}
}

通常最好不要使用
,除非
而不是
while
。它会多次否定布尔表达式,给您留下一个双负数。下面是一个示例

 while ( $foo ne $bar ) {
尽管这是一个否定表达式,但我可以很容易地确定何时退出循环。然而:

until ( $foo eq $bar ) {
只是需要时间来弄清楚

另外,''不构成空行:使用正则表达式
$cline=~/^\s*$/

until ($cline ne ' ') {
    push (@array, $cline);
}
如果
$cline
等于空白,则将永远持续。您永远不会更改
$cline
的值

您可以使用我用来调用状态变量的方法(直到Perl实际创建了一个名为的变量类型,现在我不知道该如何调用它们)此变量跟踪您在文件中的位置。您是否在文件的链段中?是否需要这些行?这样,您只有一个循环。您可以设置状态变量,然后处理循环

在本例中,我有一个名为
$keep_line
的状态变量,它询问我是否要保留我要读入的行。如果该行以
链开始,并且第二个字段大于3000,我要保留整个块(如果我理解您试图执行的操作)。(顺便问一下,我保留了空行,可以吗?)

大大简化了代码

我还要声明一些常量来删除那些神秘的MOE。这些东西像
3000
/^chain/
,在您的程序中有某种神秘但重要的意义。您可以
使用常量作为pragma来定义Perl常量。它是标准Perl的一部分:

use constant {
    KEEP_LIMIT       => 3000,
    SECTION_HEADER   => qr/^chain/,
};
现在,我可以做这样的事情:

if ( $line =~ SECTION_HEADER ) {
而不是:

if ( $line =~ /^chain/ ) {

而不是

if ( $field[1] > 3000 ) {
pragma有问题。最大的问题是它不能在Perl通常插入变量的地方插入。这包括双引号字符串和散列键。如果我有
$foo{KEEP_LIMIT}
,Perl将把键解释为字符串
KEEP\u LIMIT
,而不是
KEEP\u LIMIT
的常量


许多开发人员在很多方面都使用了更好的方法。不幸的是,
Readonly
不是一个标准的Perl模块,所以您必须通过CPAN安装它,而这有时是不可能或不可取的。因此,我倾向于使用
constant

$cline'
不是检查空行的方法。这是一种方法检查行是否正好是一个空格。
直到
只是
while
的否定,因此它没有特殊的功能,不能在那里使用,因为
while
语句分配给
$cline
。非常感谢,那么您建议我使用什么?如果您的记录上有可管理的大小,您可以使用段落模式读取它们。然后你可以在newline上拆分记录。将输入记录分隔符设置为空字符串将启用段落模式。非常感谢。我按照你的方式完成了。我相信它比现在更有效。我将进一步检查它,但我相信现在可以再次感谢你。谢谢,但我将如何放置如果我不能拆分每个“链”行以获得分数,则限制3000?@Vasilis:LHS条件可以更新,如我的编辑中所示。
if ( $line =~ /^chain/ ) {
if ( $field[1] > KEEP_LIMIT ) {
if ( $field[1] > 3000 ) {