使用perl循环遍历文件

时间:2010-07-28 19:40:58

标签: perl file loops

好的,我有2个文件。一个文件是每10分钟更新一次的数据,而第二个文件是先前使用的数据。我要做的是从新文件中取一行并循环遍历第二个文件的每一行,看看它是否匹配一个。如果它确实我不想使用它,但如果没有匹配,我想将它添加到字符串。在我到目前为止所做的事情中,似乎即使有一个检查也没有找到匹配。这是我所拥有的以及我从两个文件中使用的数据样本。 CHECKHAIL和USEDHAIL是两个文件

while(my $toBeChecked = <CHECKHAIL>){
        my $found = 0;
        seek USEDHAIL, 0, 0 or die "$0: seek: $!";
        while(my $hailCheck = <USEDHAIL>){
            if( $toBeChecked == $hailCheck){
                $found += 1;
            }
        }
        print USEDHAIL $toBeChecked;
        if ($found == 0){
            $toEmail .= $toBeChecked;
        }
    }
    print $toEmail;
    return;
}

CHECKHAIL样本数据

2226  175   2 NE      LAWRENCE           DEADWOOD         SD    44.4    -103.7  (UNR)

2305  200   2 S       SISKIYOU           GREENVIEW        CA    41.52   -122.9  2 INCH HAIL REPORTED WITH STORM JUST SOUTH OF GREENVIEW. (MFR)

2350  200             DANIELS            E FLAXVILLE      MT    48.8    -105.17 GOLF BALL TO HEN EGG SIZED HAIL (GGW)

2350  175   5 N       DANIELS            RICHLAND         MT    48.89   -106.05 DESTROYED CROPS (GGW)

USEDHAIL样本数据

2226  175   2 NE      LAWRENCE           DEADWOOD         SD    44.4    -103.7  (UNR)

2305  200   2 S       SISKIYOU           GREENVIEW        CA    41.52   -122.9  2 INCH HAIL REPORTED WITH STORM JUST SOUTH OF GREENVIEW. (MFR)

4 个答案:

答案 0 :(得分:3)

由于

,它永远不会有成功的机会
while(<USEDHAIL>){
    my $hailCheck = $_;
    if( $toBeChecked eq $hailCheck){
        $found += 1;
    }else{
        return;  ### XXX
    }
}

在第一个不匹配时,sub返回其调用者。您的意思可能是next,但为了简洁起见,您应该删除整个else子句。删除其他else { return; }(对应于$found为真时),原因相同。

请注意,您的算法具有二次复杂度,对于大输入将会很慢。最好将已使用的记录读入哈希值,然后为CHECKHAIL的每一行探测%used哈希以查看它是否已被处理。

删除这些行后,我得到了

$ ./prog.pl 

2305  200   2 S       SISKIYOU           GREENVIEW        CA    41.52   -122.9  2 INCH HAIL REPORTED WITH STORM JUST SOUTH OF GREENVIEW. (MFR)

2350  200             DANIELS            E FLAXVILLE      MT    48.8    -105.17 GOLF BALL TO HEN EGG SIZED HAIL (GGW)

2350  175   5 N       DANIELS            RICHLAND         MT    48.89   -106.05 DESTROYED CROPS (GGW)

正如您所看到的那样,仍有一个错误。您需要为USEDHAIL的每一行重新CHECKHAIL

seek USEDHAIL, 0, 0 or die "$0: seek: $!";
while(<USEDHAIL>){
...

这会产生

$ ./prog.pl 
2350  200             DANIELS            E FLAXVILLE      MT    48.8    -105.17 GOLF BALL TO HEN EGG SIZED HAIL (GGW)
2350  175   5 N       DANIELS            RICHLAND         MT    48.89   -106.05 DESTROYED CROPS (GGW)

有关更好方法的示例,请考虑

#! /usr/bin/perl

use warnings;
use strict;

sub read_used_hail {
  my($path) = @_;

  my %used;

  open my $fh, "<", $path or die "$0: open $path: $!";

  local $" = " ";  # " fix Stack Overflow highlighting
  while (<$fh>) {
    chomp;
    my @f = split " ", $_, 10;
    next unless @f;
    ++$used{"@f"};
  }

  wantarray ? %used : \%used;
}

my %used = read_used_hail "used-hail";
open my $check, "<", "check-hail" or die "$0: open: $!";

while (<$check>) {
  chomp;
  my @f = split " ", $_, 10;
  next if !@f || $used{join " " => @f};
  print $_, "\n";
}

示例运行:

$ ./prog.pl 
2350  200             DANIELS            E FLAXVILLE      MT    48.8    -105.17 GOLF BALL TO HEN EGG SIZED HAIL (GGW)
2350  175   5 N       DANIELS            RICHLAND         MT    48.89   -106.05 DESTROYED CROPS (GGW)

答案 1 :(得分:2)

为什么不为第一个(使用过的)文件创建哈希?

use strict; 
use warnings;
my %fromUsedFile;
open USEDFILE, '<', '/the/data/file/that/is/10minutesold';
$fromUsedFile{$_}++  while <USEDFILE>;
close USEDFILE;

while ($toBeChecked = <CHECKHAIL>) {
    if (defined $fromUsedFile{$toBeChecked}) {
        # ... line is in both the new and old file
    } else {
        # ... line is only in the new file
        $toBeEmailed .= $toBeChecked;
    }
}

答案 2 :(得分:1)

在内循环中使用$ _会导致问题。尝试首先命名你的行:

while(my $toBeChecked = <CHECKHAIL>){
    my $found = 0;
    while( my $hailCheck = <USEDHAIL>){

此外,perl会看到数字比较和字符串比较。您正在使用字符串比较而不是数字比较:

 if ($found eq 0){

更改为:

 if ($found == 0){

答案 3 :(得分:1)

这条线对我来说很重要:

if ($found eq 0){

由于$found是布尔值,因此对它执行布尔测试:

if (not $found) {

看起来您的逻辑有点颠倒 - 在第一个if中,如果行与不匹配则返回,然后在第二个if中返回,如果有匹配则返回。 你是否打算说next;跳过最里面的循环呢?