【问题标题】:Perl loop stuck reading file?Perl循环卡住读取文件?
【发布时间】:2010-11-05 04:28:00
【问题描述】:

结束这个问题。会喝红牛。睡觉。编写代码并返回带有单元测试用例的全新问题。

更新:新文件是here

配置文件也是here

我再次重构了代码:

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.

【问题讨论】:

  • 如果最后去掉不必要的“next;”还会出现这种情况吗?
  • 当我输入 split() 中使用的 / 字符时,它似乎会中断
  • 是的,它仍然存在。即使没有下一个!
  • split 的第一个参数是一个正则表达式。如果使用“/”作为分隔符,则需要转义模式中出现的任何字面值。或者,您可以使用其他分隔符,例如“m!pattern!”
  • 您能告诉我们您是如何确定您的代码“卡住”的吗?

标签: perl split readline while-loop


【解决方案1】:

终于搞定了!!!!!!哇睡眠是很棒的力量。

无论如何。问题出在我的 die 消息中的 $ETLSplitter::configFile 中。

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

其中有 winblows 路径分隔符“/”。所以因为我用双引号输出,perl 将路径中的 '/' 插入为模式。从这里开始

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

...  /=>/, 

这弄乱了子程序中的整个程序流程。通过这样做解决了这个问题。

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

【讨论】:

  • 我看不出第一个和最后一个 die 语句之间有什么区别。我猜当您说 winblows 时,您指的是 MS-Windows?但是从什么时候斜线在 Windows 上成为路径分隔符?这没有任何意义。对不起。
  • 是的,在我打印出 $ETLSpliter::configFile 之前,我也没有。由于本地 Intranet ip,它有 //10.0.1.1/ 它。就是这样搞砸了。
【解决方案2】:

此问题的最终帖子:根据您的最新更新,我相信以下代码说明了使用/:/ 作为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;
  }

另一个更新:

因此,根据您在下面的评论,该模式确实是 /=&gt;/。那么:

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. 如果您可以在 while 语句中执行此操作,则无需在循环主体中将 $_ 分配给 $conline

  4. 在原始代码中,您没有在@columns 中添加任何内容,也没有对$colData 进行任何有用的操作。

  5. 淡化言论。计算机的工作原理是 GIGO。

  6. the link you posted的代码,好像你不知道你可以这样做:

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

此外,看起来您正在使用哈希可以完成工作的包:

$ETLSpliter{filepath}

最后,您确实意识到Spliter 是不正确的。 ITYM:Splitter.

【讨论】:

  • 即便如此,只要我在循环中使用 / 字符,它就会中断吗?这是为什么?我在cygwin上使用perl并且文件在vim中处于[dos]模式?这会有所作为吗?
  • 因为您决定使用/ 作为模式分隔符。不,平台和编辑器没有任何区别。
  • 嗯 ...由于 split(/pattern/, $foo) 使用仍然失败。我必须使用 split('pattern', $foo)。不明白为什么会这样。我将实施您所说的更改并让我重新发布文件。
  • 你的代码是split /=&gt;/。在对您的问题的评论中,您提到在其中某处放置 /split /=&gt;/ 没有错误。你得到错误。因此,可以合理地假设您正在运行的内容和发布的内容不是一回事。
  • 如果有的话,请暂时避开红牛。
【解决方案3】:

$ETLSpliter::name 中的内容 - 任何 / 字符都应该转义。

sn-p 中的许多其他问题已经解决,所以我不会去那里。

【讨论】:

  • 为什么要在那个字符串中转义斜线?
【解决方案4】:

你确定它卡住了吗?您永远不会在 @columns 中存储任何数据,因此您的代码将始终返回一个空列表。

其他说明:

  • 您的die 调用应包括$!(操作系统错误)。除了不存在的文件之外,open 可能会失败还有其他原因,$! 会告诉您真正的问题是什么。
  • 您可能应该使用chomp $conline 来删除换行符。
  • 您可以使用while (my $conline = &lt;CFILE&gt;) 而不是从$_ 复制值。
  • 两个参数open(尤其是隐式&lt; 模式)是糟糕的形式。最好使用三参数形式(最好使用词法文件句柄):open(my $fh, '&lt;', $filename) or die...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-27
    • 2017-09-12
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多