Цикл файлов с помощью Perl - PullRequest
0 голосов
/ 28 июля 2010

Хорошо, у меня есть 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 ]

3 голосов
/ 29 июля 2010

У него никогда не было возможности преуспеть из-за

while(<USEDHAIL>){
    my $hailCheck = $_;
    if( $toBeChecked eq $hailCheck){
        $found += 1;
    }else{
        return;  ### XXX
    }
}

При первом несовпадении саб возвращается к своему вызывающему. Возможно, вы имели в виду next вместо этого, но для краткости вы должны удалить целое предложение else. Удалите другой else { return; } (соответствует тому, когда $found имеет значение true) по той же причине.

Обратите внимание, что ваш алгоритм имеет квадратичную сложность и будет медленным для больших входных данных. Было бы лучше прочитать использованные записи в хэш, а затем для каждой строки 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)
2 голосов
/ 29 июля 2010

Почему бы вам не создать хеш для первого (использованного) файла?

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;
    }
}
1 голос
/ 28 июля 2010

Эта строка выпирает у меня:

if ($found eq 0){

Поскольку $found является логическим значением, выполните для него логические тесты:

if (not $found) {

Выглядит также, как будто ваша логика немного перевернута - в первом if вы возвращаете, если строки не соответствуют , а затем во втором if вы возвращаете, если есть была спичка Возможно, вы намереваетесь сказать next;, чтобы пропустить из самого внутреннего цикла, вместо этого?

1 голос
/ 28 июля 2010

Использование $ _ во внутреннем цикле может вызвать проблемы. Попробуйте сначала назвать ваши строки так:

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

Также Perl по-разному видит числовое сравнение и сравнение строк. Вы используете сравнение строк вместо числового сравнения:

 if ($found eq 0){

Изменить на:

 if ($found == 0){
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...