为什么循环没有终止?

时间:2015-12-12 06:46:04

标签: perl

我输入文件如下......

A0FGR8 659-660 659-662
A4UGR9 728-751

我想要输出两个不同的文件(A0FGR8.diso,A4UGR9.diso),这些文件假设包含数字

659
660
661
662

之后这个for循环应该根据大数来终止,但事实并非如此。 我的perl代码如下..

#!/usr/bin/perl
open(F1,"$ARGV[0]") or die;
chomp(@list = <F1>);
close(F1);

for($i = 0; $i <= $#list; $i++) {
    @id=split(/\s+/,$list[$i]);

    open(OUT,">tmp/$id[0].diso") or die;

    for($j = $id[1]; $j = $#id; $j++) {
        ($n1, $n2) = split(/-/, $id[$j]);
        for($k = $n1; $k <= $n2; $k++) {
            print OUT "$k\n";
        }
    }
}

请告诉我我犯了哪些错误并解决了同样的错误。

2 个答案:

答案 0 :(得分:1)

这是在更健全的Perl中重写代码。所有for循环都保证终止,因为我将它们更改为使用for的列表版本而不是C样式for,这是一个良好的Perl习惯,因为列表 - {{1 很多更难以出错。

我还更改了最外面的for来直接遍历列表,而不是循环遍历索引,因为除了从列表中拉出项目之外,你实际上并没有使用索引。

for运算符从<>中列出的文件中读取(如果@ARGV为空,则从STDIN中读取),因此我对其进行了更改。很少需要明确@ARGV

最后,我更改了输出文件的open $ARGV[0]以使用词法文件句柄和open的三参数形式。两者都是推荐的做法。词法文件句柄避免使用全局变量,当它们超出范围时会自动关闭(...而您忘记了open close ...),而3-arg OUT则避免了安全漏洞给它的文件名来自程序之外。

我还让它在openstrict下干净利落地运行,两者都应该始终 warnings

修订后的代码:

use

不幸的是,我无法说明这是否会对您的数据集实际正常工作,因为您没有提供任何样本数据来对其进行测试。

答案 1 :(得分:1)

你的程序写得更清晰

你没有说你是否想要组合重叠范围,但是你自己的代码没有尝试这样做,所以我把它们保留原样,这样659和660在输出中重复到{{1 }}

A0FGR8.diso

输出

use strict; use warnings 'all'; while ( <> ) { my ($id, @ranges) = split; open my $out_fh, '>', "tmp/$id.diso" or die $!; for my $range ( @ranges ) { my ($start, $end) = split /-/, $range; print { $out_fh } "$_\n" for $start .. $end; } }

tmp/A0FGR8.diso

659 660 659 660 661 662

tmp/A4UGR9.diso


更新

这是使用Number::Range模块消除重叠范围内重复值的替代版本。它不是核心模块,因此您可能需要安装它

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751

输出

use strict; use warnings 'all'; use Number::Range; while ( <DATA> ) { my ($id, @ranges) = split; my $range = Number::Range->new; for my $interval ( @ranges ) { no warnings 'Number::Range'; $range->addrange( $interval =~ s/-/../r ); #/ } open my $out_fh, '>', "$id.diso" or die $!; print { $out_fh } "$_\n" for $range->range; } __DATA__ A0FGR8 659-660 659-662

tmp/A0FGR8.diso