我通常使用以下代码在文件中的行循环:

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

然而, 在回答另一个问题时, 埃文·卡罗尔(Evan Carroll) 编辑了我的答案,改变了我的 while 对:

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

他的理由是,如果您有一条线 0 (这必须是最后一行,否则它将有一个马车返回)然后 while 如果您使用我的陈述,将过早退出($line 将设置为 "0", ,因此分配的回报值也将是 "0" 评估为false)。如果您检查是否有定义的性,那么您将不会遇到此问题。这是完全合理的。

所以我尝试了。我创建了一个文本文件,最后一行是 0 没有马车返回。我通过循环运行它,循环没有过早退出。

然后我想:“啊哈,也许这个价值实际上不是 0, ,也许还有其他东西在搞砸了!” Dump()Devel::Peek 这就是它给我的:

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

这似乎告诉我值实际上是字符串 "0", ,如果我打电话,我会得到类似的结果 Dump() 在标量上,我明确设置为 "0" (唯一的区别是在LEN字段中 - 从文件中为80,而从标量为8的是8)。

那怎么办?为什么没有我的 while() 循环过早退出,如果我通过了一条只有一条只有 "0" 没有马车返回?是埃文的循环实际上更具防御力,还是在内部做疯狂的事情,这意味着您不必担心这些事情,并且 while() 实际上只有在您击中时才退出 eof?

有帮助吗?

解决方案

因为

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

实际上汇编到

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

在非常古老的Perl版本中可能是必要的,但不再需要!您可以从脚本上运行B :: Deparse看到这一点:

>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

所以你已经好了!

其他提示

顺便说一句,这在I/O操作员部分中涵盖 perldoc perlop:

在标量上下文中,评估角度括号中的文件打架会从该文件(如果有的话)或错误的文件或错误时产生下一行(Newline(如果有))或“ Undef”。当$/设置为“ undef”(有时称为文件弹性模式)并且文件为空时,它首次返回',然后是“ undef”。

通常,您必须将返回的值分配给变量,但是在某种情况下发生自动分配。当且仅当输入符号是“ while”语句的条件(即使被伪装成“(;;)循环)的唯一内容时,该值会自动分配给全局变量$ _,销毁任何内容以前在那里。 (这对您来说似乎是一件奇怪的事情,但是您几乎在您编写的每个perl脚本中都使用构造。)$ _变量并非隐含地本地化。您必须放置一个“本地$ _”;如果您想发生这种情况,请在循环之前。

以下行是等效的:

while (defined($_ = <STDIN>)) { print; }
while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while defined($_ = <STDIN>);
print while ($_ = <STDIN>);
print while <STDIN>;

这也表现得很类似,但避免了$ _:

while (my $line = <STDIN>) { print $line }

在这些循环构造中,然后测试了分配的值(分配是自动的还是显式),以查看是否定义了它。定义的测试避免了线路值将被视为false的问题,例如perl,例如“”或“ 0”,而没有尾随的新线。如果您确实是指此类值终止循环,则应明确测试它们:

while (($_ = <STDIN>) ne '0') { ... }
while (<STDIN>) { last unless $_; ... }

在其他布尔环境中”u003Cfilehandle>如果“使用警告” Pragma或-W命令行开关($^W变量)有效,则“没有明确”测试或比较会引起警告。

虽然是正确的 while (my $line=<$fh>) { ... } 得到 编译while (defined( my $line = <$fh> ) ) { ... } 考虑到有多次合法读取值“ 0”的合法读取,如果您没有明确的读取 defined 在循环中或测试返回 <>.

这里有几个例子:

#!/usr/bin/perl
use strict; use warnings;

my $str = join "", map { "$_\n" } -10..10;
$str.="0";
my $sep='=' x 10;
my ($fh, $line);

open $fh, '<', \$str or 
     die "could not open in-memory file: $!";

print "$sep Should print:\n$str\n$sep\n";     

#Failure 1:
print 'while ($line=chomp_ln()) { print "$line\n"; }:',
      "\n";
while ($line=chomp_ln()) { print "$line\n"; } #fails on "0"
rewind();
print "$sep\n";

#Failure 2:
print 'while ($line=trim_ln()) { print "$line\n"; }',"\n";
while ($line=trim_ln()) { print "$line\n"; } #fails on "0"
print "$sep\n";
last_char();

#Failure 3:
# fails on last line of "0" 
print 'if(my $l=<$fh>) { print "$l\n" }', "\n";
if(my $l=<$fh>) { print "$l\n" } 
print "$sep\n";
last_char();

#Failure 4 and no Perl warning:
print 'print "$_\n" if <$fh>;',"\n";
print "$_\n" if <$fh>; #fails to print;
print "$sep\n";
last_char();

#Failure 5
# fails on last line of "0" with no Perl warning
print 'if($line=<$fh>) { print $line; }', "\n";
if($line=<$fh>) { 
    print $line; 
} else {
    print "READ ERROR: That was supposed to be the last line!\n";
}    
print "BUT, line read really was: \"$line\"", "\n\n";

sub chomp_ln {
# if I have "warnings", Perl says:
#    Value of <HANDLE> construct can be "0"; test with defined() 
    if($line=<$fh>) {
        chomp $line ;
        return $line;
    }
    return undef;
}

sub trim_ln {
# if I have "warnings", Perl says:
#    Value of <HANDLE> construct can be "0"; test with defined() 
    if (my $line=<$fh>) {
        $line =~ s/^\s+//;
        $line =~ s/\s+$//;
        return $line;
    }
    return undef;

}

sub rewind {
    seek ($fh, 0, 0) or 
        die "Cannot seek on in-memory file: $!";
}

sub last_char {
    seek($fh, -1, 2) or
       die "Cannot seek on in-memory file: $!";
}

我并不是说这些是Perl的好形式! 我是说他们是可能的。尤其是失败3,4和5。请注意,第4和5号的失败没有警告。前两个有自己的问题...

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top