代码之家  ›  专栏  ›  技术社区  ›  shinjuo

用perl遍历文件

  •  0
  • shinjuo  · 技术社区  · 14 年前

    好的,我有两份档案。一个文件是每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;
    }
    

    检查样本数据

    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 回复  |  直到 14 年前
        1
  •  2
  •   mob    14 年前

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

    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
  •  3
  •   Greg Bacon    14 年前

    它从来没有成功的机会,因为

    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)

    正如你所看到的,它仍然有一个bug。你需要倒带 USEDHAIL 冰雹 :

    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丹尼尔E弗拉克斯维尔山脉48.8-105.17高尔夫球到鸡蛋大小的冰雹(GGW)
    2350 175 5 N DANIELS RICHLAND MT 48.89-106.05毁坏的作物(GGW)
        3
  •  1
  •   Cfreak    14 年前

    在内部循环中使用$可能会导致问题。试着先给你的台词命名如下:

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

    perl对数值比较和字符串比较的看法也不同。您使用的是字符串比较而不是数字比较:

     if ($found eq 0){
    

    更改为:

     if ($found == 0){
    
        4
  •  1
  •   Ether    14 年前

    if ($found eq 0){
    

    $found 是布尔值,对其执行布尔测试:

    if (not $found) {
    

    看起来你的逻辑也有点颠倒了——首先 if 不匹配 ,然后在第二个 ,如果有匹配项,则返回。 next; 跳出最里面的循环?