Perl зациклился на чтении файла? - PullRequest
0 голосов
/ 23 июня 2009

Закрытие этого вопроса. Будем пить красный бык. Спать. Зашифруйте и вернитесь с новым порочным вопросом с юнит-тестами.

ОБНОВЛЕНИЕ: новый файл здесь

Также файл конфигурации здесь

Я снова изменил код:

sub getColumns {
    open my $input, '<', $ETLSplitter::configFile
        or die "Error opening '$ETLSpliter::configFile': $!";

    my $cols;
    while( my $conline = <$input> ) {
        chomp $conline;
        my @values = split (/=>/, $conline);
        if ($ETLSplitter::name =~ $values[0] ) {
            $cols = $values[1];
            last;
        }
    }

    if($cols) {
        @ETLSplitter::columns = split (':', $cols);
    }
    else {
        die("$ETLSplitter::name is not specified in the config file");
    }
}

Этот код всегда умирает здесь die("$ETLSplitter::name is not specified in the config file");.

Другая подсказка заключается в том, что если я изменю split (':', $cols); на split (/:/, $cols);, я получу эту ошибку.

 perl -wle "
 use modules::ETLSplitter;
 \$test = ETLSplitter->new('cpr_operator_metric_actual_d2', 'frame/');
 \$test->prepareCSV();"
 syntax error at modules/ETLSplitter.pm line 154, near "}continue"
 Compilation failed in require at -e line 2.
 BEGIN failed--compilation aborted at -e line 2.

Ответы [ 4 ]

6 голосов
/ 23 июня 2009

ЗАКЛЮЧИТЕЛЬНОЕ ПОСЛАНИЕ ДЛЯ ЭТОГО ВОПРОСА: Основываясь на ваших последних обновлениях, я полагаю, что следующий код иллюстрирует, как нет проблем с использованием /:/ в качестве первого аргумента split. Это также указывает на то, что легче читать код, когда кто-то использует аргументы для функций, а не полагается на глобальные переменные:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

for my $varname ( qw( adntopr.cpr.smtref.actv cpr_operator_detail )) {
    print $varname, "\n";
    print Dumper get_columns(\*DATA, $varname);
}

sub get_columns {
    my ($input_fh, $varname) = @_;

    while ( my $line = <$input_fh> ) {
        chomp $line;
        my @values = split /=>/, $line;
        next unless $varname eq $values[0];
        return [ split /:/, $values[1] ];
    }
    return;
}

__DATA__
adntopr.cpr.smtref.actv=>3:8:18:29:34:38:46:51:53:149
adntopr.smtsale2=>3:8:16:22:27:37:39:47:52:57:62:82:102:120:138:234:239:244:249:250:259:262:277:282:287:289:304:319:327:331:335:339:340:341:342:353:364:375:386:397:408
cpr_operator_detail=>3:11:18:28:124:220:228:324
cpr_operator_org_unit_map=>7:12
cpr_operator_metric_actual=>8:15:25:33:38:40:51

C:\Temp> tjm
adntopr.cpr.smtref.actv
$VAR1 = [
          '3',
          '8',
          '18',
          '29',
          '34',
          '38',
          '46',
          '51',
          '53',
          '149'
        ];
cpr_operator_detail
$VAR1 = [
          '3',
          '11',
          '18',
          '28',
          '124',
          '220',
          '228',
          '324'
        ];

В этом коде много ошибок. Вот моя интерпретация того, что вы пытаетесь сделать:

ОБНОВЛЕНИЕ: Учитывая ваше недавнее замечание о специальных символах регулярных выражений в шаблонах, если вы собираетесь использовать их в шаблоне для разделения, обязательно заключите их в кавычки. Также существует вероятность, что $ETLSpliter::name может содержать другие специальные символы. Я изменил код, чтобы справиться с этой возможностью.

sub getColumns {
    open my $input, '<', $ETLSpliter::configFile
          or die "Error opening '$ETLSpliter::configFile': $!");
      my @columns;
      while( my $conline = <$input> ) {
          my @values = split /=>/, $conline;
          print "not at: ".$conline;
          push @columns, $values[1] if $values[0] =~ /\Q$ETLSpliter::name/;
      }
      return @columns;
  }

ДРУГОЕ ОБНОВЛЕНИЕ:

Итак, шаблон действительно равен /=>/ на основании вашего комментария ниже. Тогда:

my $conline = q{cpr_operator_detail=>3:11:18:28:124:220:228:324};
my @values = split /=>/, $conline;

use Data::Dumper;
print Dumper \@values;
__END__

C:\Temp> tml
$VAR1 = [
          'cpr_operator_detail',
          '3:11:18:28:124:220:228:324'
        ];

Нет ошибок ... Нет предупреждений Поэтому происходит еще кое-что, что вы настаиваете на том, чтобы не показывать нам.

Другие замечания:

  1. Используйте лексические файловые дескрипторы и пусть Perl скажет вам, с какими ошибками он может столкнуться, а не предположить.

  2. Объявите переменные в наименьшей применимой области.

  3. Нет необходимости присваивать $_ для $conline в теле цикла, когда вы можете сделать это в операторе while.

  4. В исходном коде вы ничего не помещали в @columns или не делали ничего полезного с $colData.

  5. Приглушите риторику. Компьютеры работают по принципу GIGO.

  6. Глядя на код по ссылке, которую вы разместили , похоже, что вы не знаете, что можете сделать:

    use File::Spec::Functions qw( catfile );
    ...
    catfile($ETLSpliter::filepath_results, $ETLSpliter::actual_name);
    

Кроме того, похоже, что вы используете пакет, в котором хэш бы выполнил свою работу:

$ETLSpliter{filepath}

Наконец, вы понимаете, Spliter неверно. ITYM: Splitter.

3 голосов
/ 23 июня 2009

Вы уверены, что он застрял? Вы никогда не сохраняете данные в @columns, поэтому ваш код всегда будет возвращать пустой список.

Другие примечания:

  • Ваш die вызов должен включать $! (ошибка ОС). Есть и другие причины, по которым open может завершиться ошибкой, кроме несуществующего файла, и $! скажет вам, в чем была настоящая проблема.
  • Вы, вероятно, должны сделать chomp $conline, чтобы избавиться от новой строки.
  • Вы можете сделать while (my $conline = <CFILE>) вместо копирования значения из $_.
  • Два аргумента open (особенно с неявным режимом <) - плохая форма. Использование формы с тремя аргументами (в идеале с лексическим дескриптором файла) является предпочтительным: open(my $fh, '<', $filename) or die...
1 голос
/ 23 июня 2009

Что в $ETLSpliter::name - любые символы / должны быть экранированы.

Многие другие проблемы во фрагменте уже рассмотрены, поэтому я не буду туда заходить.

0 голосов
/ 23 июня 2009

НАКОНЕЦ ВЫЯВЛЕН! Вау, сон - это потрясающая сила.

В любом случае. Проблема была в $ ETLSplitter :: configFile в моем сообщении.

die ('Error opening '.$ETLSpliter::configFile.': '.$!);

У которого есть разделители пути winblows '/'. Таким образом, поскольку я выводил в двойных кавычках, perl интерпретировал символ '/' в пути как шаблоны. Отсюда

die "Error opening some/path/to/ ...

до

...  /=>/, 

Который перепутал весь поток программ в подпрограмме. Это было решено, делая это.

die ('Error opening '.$ETLSpliter::configFile.': '.$!);
...