Perl 嵌套循环比较两个文件时,外部循环在一次迭代后停止,需要比较每一行文件

Perl 嵌套循环比较两个文件时,外部循环在一次迭代后停止,需要比较每一行文件,perl,loops,Perl,Loops,首先,如果我在这里的格式不正确,我表示歉意,我对写脚本非常陌生(3天),这是我在这个网站上的第一篇帖子 我有两个分开的文件,filea包含14列,fileb包含8列 文件b中的一列有一个数值,该数值与文件a中两个数值字段生成的一系列数字相关。 对于文件a中的每一行,我需要搜索文件b,并打印两个文件上字段的数据组合。由于接受了一个数字范围,文件a的每一行都将有多个匹配项 我创建的代码完全符合我的要求,但只针对文件a的第一行,不会继续循环。我浏览了整个互联网,我相信这可能与两个文件都是从标准输入读取

首先,如果我在这里的格式不正确,我表示歉意,我对写脚本非常陌生(3天),这是我在这个网站上的第一篇帖子

我有两个分开的文件,
filea
包含14列,
fileb
包含8列

文件b
中的一列有一个数值,该数值与
文件a
中两个数值字段生成的一系列数字相关。 对于
文件a
中的每一行,我需要搜索
文件b
,并打印两个文件上字段的数据组合。由于接受了一个数字范围,文件a的每一行都将有多个匹配项

我创建的代码完全符合我的要求,但只针对
文件a
的第一行,不会继续循环。我浏览了整个互联网,我相信这可能与两个文件都是从标准输入读取的事实有关。我试图纠正这个问题,但似乎什么都没用

我目前的理解是,通过将一个文件更改为从不同的文件描述符读取,我的循环可能会工作。。。比如说,
$3
,但尽管我做了研究,我还是不太明白这一点。或者可能使用我也在努力使用的
grep
功能

下面是我现在使用的代码的概要:

use strict;  
use warnings;

print "which file read from?\n";
my $filea = <STDIN>;  
chomp $filea;  
{
  unless (open ( FILEA, $filea) {
      print "cannot open, do you want to try again? y/n?\n?";  
      my $attempt = <STDIN>;  
      chomp $again;  
      if ($again =~ 'n') {
          exit;  
      } else {
          print "\n";   
          $filea = <STDIN>;  
          chomp $filea;  
          redo;  
      }
   }
}

#I also open fileb the same way, but wont write it all out to save space and your time.

my output = 'output.txt';  
open (OUTPUT, ">>$output");    

while (my $loop1 = <FILEA>) {  
    chomp $loop1;
    ( my $var1, my $var2, my $var3, my $var4, my $var5, my $var6, 
      my $var7, my $var8, my $var9, my $var10, my $var11, my $var12, 
      my $var13, my $var14 ) = split ( "\t", $loop1);

  #create the range of number which needs to be matched from file b.
  my $length = length ($var4);  
  my $range = ($var2 + $length);

  #perform the search loop through fileb
  while (my $loop2 = <FILEB>) {
      chomp $loop2;
    ( my $vala, my $valb, my $valc, my $vald, my $vale, my $valf, 
      my $valg) = split ( "\t", $loop2 );

    #there are then several functions and additions of the data, which all work basicly so I'll just use a quick example.

    if ($vald >= $val3 $$ $vald <= $range) {
        print OUTPUT "$val1, $vald, $val11, $valf, $vala, $val5 \n";
    }
  }
}
使用严格;
使用警告;
打印“从哪个文件读取?\n”;
我的$filea=;
咀嚼$filea;
{
除非(打开(FILEA,$FILEA){
打印“无法打开,是否重试?是/否?\n?”;
我的$尝试=;
再次咀嚼美元;
如果($再次=~'n'){
出口
}否则{
打印“\n”;
$filea=;
咀嚼$filea;
重做;
}
}
}
#我也以同样的方式打开fileb,但不会为了节省空间和时间而全部写出来。
我的输出='output.txt';
打开(输出“>>$OUTPUT”);
而(我的$loop1=){
chomp$loop1;
(我的$var1,我的$var2,我的$var3,我的$var4,我的$var5,我的$var6,
我的$var7,我的$var8,我的$var9,我的$var10,我的$var11,我的$var12,
my$var13,my$var14)=拆分(“\t”,$loop1);
#从文件b中创建需要匹配的数字范围。
my$length=长度($var4);
我的$range=($var2+$length);
#通过fileb执行搜索循环
而(我的$loop2=){
chomp$loop2;
(我的$vala,我的$valb,我的$valc,我的$vald,我的$vale,我的$valf,
my$valg)=拆分(“\t”,$loop2);
#然后有几个函数和数据的添加,它们基本上都可以工作,所以我将使用一个简单的示例。
如果($vald>=$val3$$$vald
  • 尽可能避免裸句柄;使用$fh(filehandle)代替fh

  • 您可以使用直到而不是除非,并跳过重做:

    print "Enter the file name\n";
    my $file_a = <STDIN>;
    chomp $file_a;
    my $fh_a;
    until(open $fh_a, '<', $file_a) {
        print "Re-enter the file name or 'n' to cancel\n";
        $file_a = <STDIN>;
        chomp $file_a;
        if($file_a eq 'n') {
            exit;
        }
    }
    

  • 等是否实际在反勾中,或者这只是格式化的产物(如果是,请编辑您的问题以删除它们)?您是否已经了解其他编程语言?您从哪些资源(哪些教程等)学习?无论如何,您的关键错误实际上很常见:当您到达
    FILEA
    的第二行时,您已经用尽了
    FILEB
    句柄。因此,我们需要将文件句柄重置为开头,或者在循环中重新打开文件,或者将整个文件读取到内存中。其他人可以编写该答案。提示:
    (my$x,my$y,my$z)
    可以写成
    my($x,$y,$z)
    。提示:
    my($var1,$var2,$var3,$varn)
    最好写成
    my@var
    ,然后称为
    $var[0],$var[1],…$var[$n]
    .Thr backticks只是格式化工件,我编辑了问题以删除它们。我根本不懂任何编程语言,我决定在我的学位期末考试中第一次尝试编程。我从几本书中学习过,比如《生物信息学的perl入门》和《出现问题时的谷歌搜索》。谢谢对于这个答案,我有这么多的提示,我现在已经设法让一切工作,这是非常棒的!我也更了解我造成的整个问题,这正是我所需要的。我知道代码将需要优化,一旦我变得更加熟练,我可能会再次解决这个问题。
    #Assume we have opened both files already . . .
    my @file_b = <$fh_b>;
    chomp @file_b;
    while(my $line = <$fh_a>) {
        chomp $line;
        my @cols_a = split /\t/, $line;
        #Remember, most arrays (perl included) are zero-indexed,
        #so $cols_a[1] is actually the SECOND column.
        my $range = ($cols_a[1] + length $cols_a[3]);
    
        foreach my $line_b (@file_b) {
            #This loop will run once for every single line of file A.
            #Not efficient, but it will work.
            #There are, of course, lots of optimisations you can make
            #(starting with, for example, storing file B as an array of array
            #references so you don't have to split each line every time)
            my @cols_b = split /\t/, $line_b;
            if($cols_b[3] > $cols_a[2] && $cols_b[3] < ($cols_a[2] + $range)) {
                #Do whatever here
            }
        }
    }