Perl 循环读取文件卡住?

发布于 2024-07-26 01:17:47 字数 1354 浏览 3 评论 0原文

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

更新:新文件位于此处< /a>

配置文件也在这里

我再次重构了代码:

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");.

另一个线索是,如果我将 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.

Closing this question. Will drink red bull. Sleep. Code and come back with brand spanking new question with unit test cases.

UPDATE: The new file is here

Also the config file is here

I refactored the code again:

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");
    }
}

This code always dies here die("$ETLSplitter::name is not specified in the config file");.

Another clue is that if I change split (':', $cols); to split (/:/, $cols); I get this error.

 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

拥抱影子 2024-08-02 01:17:47

此问题的最终帖子:根据您的最新更新,我相信以下代码说明了使用 /:/ 作为 的第一个参数如何没有问题拆分。 它还指出,当人们使用函数参数而不是依赖全局变量时,阅读代码会更容易:

#!/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. 当您可以在 while 语句中执行此操作时,无需在循环体中将 $_ 分配给 $conline。< /p>

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

  5. 缓和言辞。 计算机按照 GIGO 原理工作。

  6. 查看您发布的链接处的代码,看起来您并没有意识到您可以做:

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

此外,看起来你正在使用一个散列可以完成这项工作的包:

$ETLSpliter{filepath}

最后,你确实意识到 Spliter 是不正确的。 ITYM:分离器

FINAL POST FOR THIS QUESTION: Based on your latest updates, I believe the following code illustrates how there is no problem with using /:/ as the first argument to split. It also points out that it is easier to read code when one uses arguments to functions rather than relying on global variables:

#!/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'
        ];

There is a lot of cruft in that code. Here is my interpretation of what you are trying to do:

UPDATE: Given your recent remark about regex special characters in patterns, if you are going to use them in the pattern to split, make sure to quote them. There is also a chance that $ETLSpliter::name might contain other special characters. I modified the code to deal with that possibility.

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;
  }

ANOTHER UPDATE:

So, the pattern indeed is /=>/ based on your comment below. Then:

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'
        ];

No errors ... No warnings Therefore, there is something else that is going on which you insist on not showing us.

Other Remarks:

  1. Use lexical filehandles and let perl tell you what errors it may encounter rather than presuming.

  2. Declare variables in the smallest applicable scope.

  3. No need to assign $_ to $conline in the body of the loop when you can do that in the while statement.

  4. In the original code, you were not putting anything in @columns or doing anything useful with $colData.

  5. Tone down the rhetoric. Computers work on the principle of GIGO.

  6. Looking at the code at the link you posted, it looks like you are not aware that you can do:

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

Further, it looks like you are using a package where hash would have done the job:

$ETLSpliter{filepath}

Finally, you do realize Spliter is incorrect. ITYM: Splitter.

千里故人稀 2024-08-02 01:17:47

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

其他注意事项:

  • 您的 die 调用应包含 $! (操作系统错误)。 除了文件不存在之外,还有其他原因导致 open 失败,$! 会告诉您真正的问题是什么。
  • 您可能应该执行 chomp $conline 来删除换行符。
  • 您可以执行 while (my $conline =) 而不是从 $_ 复制值。
  • 双参数 open(特别是隐式 < 模式)的形式很差。 首选使用三参数形式(最好使用词法文件句柄):open(my $fh, '<', $filename) or die...

Are you sure that it's stuck? You never store any data in @columns, so your code will always return an empty list.

Other notes:

  • Your die call should include $! (OS error). There are other reasons that the open could fail besides a non-existent file, and $! will tell you what the real problem was.
  • You should probably do a chomp $conline to get rid of the newline.
  • You can do while (my $conline = <CFILE>) instead of copying the value from $_.
  • Two-argument open (particularly with an implicit < mode) is poor form. Using the three-argument form (ideally with a lexical filehandle) is preferred: open(my $fh, '<', $filename) or die...
旧梦荧光笔 2024-08-02 01:17:47

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

代码片段中的许多其他问题已经得到解决,所以我不会去那里。

What's in $ETLSpliter::name - any / chars there should be escaped.

Many other issues in the snippet have already been addressed so I won't go there.

时光暖心i 2024-08-02 01:17:47

终于弄清楚了!!!! 哇,睡眠是一种神奇的力量。

反正。 问题出在我的死亡消息中的 $ETLSplitter::configFile 中。

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

其中有 winblows 路径分隔符“/”。 因为我用双引号输出,perl 将路径中的“/”解释为模式。 从这里

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

...  /=>/, 

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

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

FINALLY FIGURED IT OUT!!!!! Wow Sleep is awesome power.

Anyway. The problem was in $ETLSplitter::configFile in my die message.

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

Which has winblows path separators '/'. So because I was outputting in double quotation, perl interperted the '/' in the path as patterns. From here

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

to

...  /=>/, 

Which messed with the entire program flow in the subroutine. This was solved by doing this.

die ('Error opening '.$ETLSpliter::configFile.': '.$!);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文