本文介绍了使用 Perl 遍历文件中的行的最防御性方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常使用以下代码遍历文件中的行:

I usually loop through lines in a file using the following code:

open my $fh, '<', $file or die "Could not open file $file for reading: $!\n";
while ( my $line = <$fh> ) {
  ...
}

然而,在回答另一个问题时Evan Carroll 编辑了我的答案,同时更改了我的 语句:

However, in answering another question, Evan Carroll edited my answer, changing my while statement to:

while ( defined( my $line = <$fh> ) ) {
  ...
}

他的理由是,如果你有一行是 0(它必须是最后一行,否则会有回车)那么你的 while如果您使用我的语句($line 将设置为 "0",因此赋值的返回值也将是 "0" 被评估为假).如果您检查定义性,那么您就不会遇到这个问题.说得很有道理.

His rationale was that if you have a line that's 0 (it'd have to be the last line, else it would have a carriage return) then your while would exit prematurely if you used my statement ($line would be set to "0", and the return value from the assignment would thus also be "0" which gets evaluated to false). If you check for defined-ness, then you don't run into this problem. It makes perfect sense.

所以我试了一下.我创建了一个文本文件,它的最后一行是 0 没有回车.我在我的循环中运行它,循环没有过早退出.

So I tried it. I created a textfile whose last line is 0 with no carriage return on it. I ran it through my loop and the loop did not exit prematurely.

然后我想,啊哈,也许值实际上不是 0,也许还有其他东西把事情搞砸了!"所以我使用了 Devel::Peek 中的 Dump(),这就是它给我的:

I then thought, "Aha, maybe the value isn't actually 0, maybe there's something else there that's screwing things up!" So I used Dump() from Devel::Peek and this is what it gave me:

SV = PV(0x635088) at 0x92f0e8
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0X962600 "0"\0
  CUR = 1
  LEN = 80

这似乎告诉我该值实际上是字符串 "0",因为如果我在标量上调用 Dump() 会得到类似的结果 I'已明确设置为 "0"(唯一的区别在于 LEN 字段——来自文件的 LEN 为 80,而来自标量的 LEN 为 8).

That seems to tell me that the value is actually the string "0", as I get a similar result if I call Dump() on a scalar I've explicitly set to "0" (the only difference is in the LEN field -- from the file LEN is 80, whereas from the scalar LEN is 8).

那是怎么回事?为什么我的 while() 循环不会过早退出,如果我向它传递只有 "0" 没有回车的行?Evan 的循环实际上是更具防御性,还是 Perl 在内部做了一些疯狂的事情,这意味着您不需要担心这些事情并且 while() 实际上只有在您点击 eof?

So what's the deal? Why doesn't my while() loop exit prematurely if I pass it a line that's only "0" with no carriage return? Is Evan's loop actually more defensive, or does Perl do something crazy internally that means you don't need to worry about these things and while() actually only does exit when you hit eof?

推荐答案

因为

 while (my $line = <$fh>) { ... }

实际上编译为

 while (defined( my $line = <$fh> ) ) { ... }

在非常旧的 perl 版本中可能需要它,但现在不再需要了!您可以通过在脚本上运行 B::Deparse 来看到这一点:

It may have been necessary in a very old version of perl, but not any more! You can see this from running B::Deparse on your script:

>perl -MO=Deparse
open my $fh, '<', $file or die "Could not open file $file for reading: $!\n";
while ( my $line = <$fh> ) {
  ...
}

^D
die "Could not open file $file for reading: $!\n" unless open my $fh, '<', $file;
while (defined(my $line = <$fh>)) {
    do {
        die 'Unimplemented'
    };
}
- syntax OK

所以你已经可以开始了!

So you're already good to go!

这篇关于使用 Perl 遍历文件中的行的最防御性方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 22:35