2012-08-13 196 views
0

它应该是一个简单的嵌套的foreach循环,但它不工作,真的开始烦我,我无法弄清楚这一点!仍然是perl初学者,但我认为我现在已经明白了这一点。有人可以向我解释我哪里出错了吗?这个想法很简单:2个文件,1个小,1个大的信息,我想在小的一个。两者都有独特的身份证件。比较和匹配ID,并输出一个新的小文件,并在小文件中添加信息。嵌套的foreach循环不工作

我有2件代码:1没有严格和1与两者都不工作。我知道使用限制,但我仍然很好奇,为什么没有限制的人也没有工作。

不用其他STRICTS:

if ($#ARGV != 2){ 
print "input_file1 input_file2 output_file\n"; 
exit; 
} 

$inputfile1=$ARGV[0]; 
$inputfile2=$ARGV[1]; 
$outputfile1=$ARGV[2]; 

open(INFILE1,$inputfile1) || die "No inputfile :$!\n"; 
open(INFILE2,$inputfile2) || die "No inputfile :$!\n"; 
open(OUTFILE_1,">$outputfile1") || die "No outputfile :$!\n"; 

$i = 0; 
$j = 0; 

@infile1=<INFILE1>; 
@infile2=<INFILE2>; 

foreach (@infile1){ 
    @elements = split(";",$infile1[$i]); 

    $id1 = $elements[3]; 
    print "1. $id1\n"; 

    $lat = $elements[5]; 
    $lon = $elements[6]; 

    $lat =~ s/,/./; 
    $lon =~ s/,/./; 

    print "2. $lat\n"; 
    print "3. $lon\n"; 

    foreach (@infile2){ 
     @loopelements = split(";",$infile2[$j]); 

     $id2 = $loopelements[4]; 

     print "4. $id2\n"; 

     if ($id1 == $id2){ 
     print OUTFILE_1 "$loopelements[0];$loopelements[1];$loopelements[2];$loopelements[3];$loopelements[4];$lat,$lon\n"; 
     }; 

     $j = $j+1; 
     }; 

    @elements = join(";",@elements); # add ';' to all elements 
    #print "$i\r"; 
    $i = $i+1; 
    } 
close(INFILE1); 
close(INFILE2); 
close(OUTFILE_1); 

没有是,如果我没有记错的第二循环将无法启动的错误。

WITH STRICTS

use strict; 
use warnings; 

my $inputfile1 = shift || die "Give input!\n"; 
my $inputfile2 = shift || die "Give more input!\n"; 
my $outputfile = shift || die "Give output!\n"; 

open my $INFILE1, '<', $inputfile1 or die "In use/Not found :$!\n"; 
open my $INFILE2, '<', $inputfile2 or die "In use/Not found :$!\n"; 
open my $OUTFILE, '>', $outputfile or die "In use/Not found :$!\n"; 

my $i = 0; 
my $j = 0; 

foreach (my $infile1 = <$INFILE1>){ 
    my @elements = split(";",$infile1[$i]); 

    my $id1 = $elements[3]; 
    print "1: $id1\n"; 

    my $lat = $elements[5]; 
    my $lon = $elements[6]; 

    $lat =~ s/,/./; 
    $lon =~ s/,/./; 

    print "2: $lat\n"; 
    print "3: $lon\n"; 

    foreach (my $infile2 = <$INFILE2>){ 
     my @loopelements = split(";",$infile2[$j]); 

     my $id2 = $loopelements[4]; 

     print "4: $id2\n"; 

     if ($id1 == $id2){ 
     print $OUTFILE "$loopelements[0];$loopelements[1];$loopelements[2];$loopelements[3];$loopelements[4];$lat,$lon\n"; 
     }; 

    $j = $j+1; 
    }; 

    #@elements = join(";",@elements); # add ';' to all elements 
    #print "$i\r"; 
    $i = $i+1; 
    } 
close($INFILE1); 
close($INFILE2); 
close($OUTFILE); 

与stricts错误:

Global symbol "@infile1" requires explicit package name at Z:\Data-Content\Data\test\jan\bestemming_zonder_acco\add_latlon_dest_test.pl line 16. 
Global symbol "@infile2" requires explicit package name at Z:\Data-Content\Data\test\jan\bestemming_zonder_acco\add_latlon_dest_test.pl line 31. 

回答

2

你的 '严格' 执行给你的错误是由于一个关于印记(的$和@字符)混淆指示是否一个变量是一个标量或一个数组。在循环语句中,您正在将文件的每一行读入一个名为$ infile1的标量,但是在下面的行中,您正试图访问数组@ infile1的一个元素。这些变量是不相关的,因为perl告诉你后者没有声明。

“严格”实现的另一个问题是您正在读取循环内的文件。这意味着对于嵌套循环,您将在外循环的第一次迭代中读取文件2,对于所有后续迭代,内循环将无法读取任何行。

我错过了foreach/while问题,由stevenl指出,即使修复了这些狭窄问题,也只会导致一次循环的foreach循环。

我不确定你的问题与无限脚本是什么。

但我不会使用嵌套循环来处理两个文件。我会取消嵌套循环,所以它大致看起来像这样:

my %cord; 
while (my $line = <$INFILE1>) { 
    my @elements = split /;/, $line; 

    $cord{ $elements[3] } = "$elements[5],$elements[6]"; 
} 

while (my $line = <$INFILE2>) { 
    my @elements = split /;/, $line; 

    if (exists %coord{ $elements[4] }) { 
     print $OUTFILE "....;$cord{ $elements4 }\n"; 
    } 
} 
+0

啊,谢谢你解释它!我认为我的非严格版本的问题是它没有循环。但我想我在这里有足够的解释来查看我的错误。我知道,我更喜欢一个while循环,但我也想明白这一点(不适用于学校或类似的东西) – Jan 2012-08-13 13:08:41

+0

正如dan1111指出的那样,非严格版本正在循环(通过@ infile2的元素)。但是,当你试图自己跟踪一个指数计数器,但忘记重置它时,$ infile2 [$ j]在大多数时间都将是'undef'。 – pmakholm 2012-08-13 13:25:47

1

我不能看到确切的问题与非严格版本的位置。你遇到的问题是什么?

与严格的版本问题是,特别是在这两条线:

foreach (my $infile1 = <$INFILE1>){ 
    my @elements = split(";",$infile1[$i]); 

你必须在第一行标$infile1,但你把它当作下一行的数组。另外,将foreach更改为while(请参见下文)。

有几点意见。

  • 对于非严格的版本,你可能会崩溃循环到C风格for环路:

    for (my $i = 0; $i < @infile1; $i++) { 
        ... 
    } 
    
  • 可以做出简单的阅读,如果你去,而不阵列指数共:

    foreach my $infile1 (@infile1) { 
        my @elements = split ';', $infile1; 
        ... 
    } 
    
  • 但与较大的文件,它可能需要一段时间才能将整个文件啜到开头的阵列。所以它可能是更好的通过文件进行迭代,当您去:

    while (my $infile = <$INFILE1>) { 
        ... 
    } 
    
  • 注意最后一点应该是严格的版本的外观。你需要一个while循环而不是一个foreach循环,因为将<$INFILE1>分配给标量意味着它只返回下一行,只要文件中有另一行,它就返回true。 (因此,foreach永远只能拿到第一线循环结束了。)

+0

我的问题是没有循环,但现在很清楚。谢谢你指出我在代码中犯了什么错误。我正在处理它.. – Jan 2012-08-13 13:10:17

0

你不内foreach循环运行之前重置附加$ J。因此,第二次内部循环运行时,您正试图访问超出数组末尾的元素。这个错误存在于严格版本和非严格版本中。

你不应该使用$ i和$ j; foreach的一点是,它会自动获取你的每个元素。这是在内部循环使用正确的foreach的例子:

foreach my $line (@infile2){ 
    @loopelements = split(";",$line); 

    #...now do stuff as before 
} 

这使@InFile一个的每个元素为连续变量$线,直到你已经完成了所有阵列的走了。

+0

注意:我也同意其他人指出严格版本的问题。这是为了解释非严格版本有什么问题。 – dan1111 2012-08-13 11:15:56