Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';使用Perl在文件中循环行的最具防御性的方法是什么?_Perl_While Loop_Defensive Programming - Fatal编程技术网

什么';使用Perl在文件中循环行的最具防御性的方法是什么?

什么';使用Perl在文件中循环行的最具防御性的方法是什么?,perl,while-loop,defensive-programming,Perl,While Loop,Defensive Programming,我通常使用以下代码循环文件中的行: open my $fh, '<', $file or die "Could not open file $file for reading: $!\n"; while ( my $line = <$fh> ) { ... } 他的基本原理是,如果您有一行0(它必须是最后一行,否则它将有回车符),那么如果您使用我的语句,您的while将过早退出($line将设置为“0”,并且分配的返回值也因此将是“0”,计算结果为false)。如果您检查

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

open my $fh, '<', $file or die "Could not open file $file for reading: $!\n";
while ( my $line = <$fh> ) {
  ...
}
他的基本原理是,如果您有一行
0
(它必须是最后一行,否则它将有回车符),那么如果您使用我的语句,您的
while
将过早退出(
$line
将设置为
“0”
,并且分配的返回值也因此将是
“0”
,计算结果为false)。如果您检查定义的模糊性,则不会遇到此问题。这很有道理

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

然后我想,“啊哈,也许这个值实际上不是
0
,也许还有别的东西把事情搞砸了!”所以我使用了
Devel::Peek
中的
Dump()
,它给了我以下信息:

SV = PV(0x635088) at 0x92f0e8
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0X962600 "0"\0
  CUR = 1
  LEN = 80
这似乎告诉我,该值实际上是字符串
“0”
,因为如果我对已显式设置为
“0”
的标量调用
Dump()

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

因为

 while (my $line = <$fh>) { ... }
while(my$line=){…}
实际上编译成

 while (defined( my $line = <$fh> ) ) { ... }
while(已定义(my$line=){…}
在非常旧的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
perl-MO=Deparse
打开我的$fh,“顺便说一句,这在以下的I/O操作员部分中介绍:

在标量上下文中,对尖括号中的文件句柄求值会产生该文件的下一行(换行符,如果有的话),或者在文件末尾或出错时产生“undef”。当$/设置为“undef”(有时称为文件slurp模式)且文件为空时,它第一次返回“”,随后返回“undef”

通常必须将返回值赋给变量,但有一种情况会发生自动赋值。如果且仅当输入符号是“while”语句的条件内的唯一内容(即使伪装为“for(;))”循环),该值将自动分配给全局变量$\ux,从而销毁以前存在的任何内容。(这对您来说可能是一件奇怪的事情,但您将在编写的几乎每一个Perl脚本中使用该构造。)$变量不是隐式本地化的。如果希望发生这种情况,则必须在循环前面加上“local$\”

以下几行是等效的:

while (defined($_ = <STDIN>)) { print; }
while ($_ = <STDIN>) { print; }
while (<STDIN>) { print; }
for (;<STDIN>;) { print; }
print while defined($_ = <STDIN>);
print while ($_ = <STDIN>);
print while <STDIN>;
while(已定义($\u=){print;}
而($=){print;}
while(){print;}
对于(;){print;}
定义时打印($=);
边打印边打印($);
边打印边打印;
这也具有类似的行为,但避免了$\

while (my $line = <STDIN>) { print $line }
while(my$line=){print$line}
在这些循环构造中,然后测试分配的值(分配是自动的还是显式的),以查看它是否已定义。定义的测试避免了以下问题:行中的字符串值将被Perl视为false,例如“”或没有尾随换行符的“0”。如果您确实想让这些值终止循环,则应明确测试它们:

while (($_ = <STDIN>) ne '0') { ... }
while (<STDIN>) { last unless $_; ... }
while($=)ne'0'){…}
while(){last除非$}
在其他布尔上下文中,如果“use warnings”pragma或-w命令行开关($^w变量)有效,则在没有显式“defined”测试或比较的情况下,会引发警告


<> p> >“代码”>(我的$LIN=){…} /代码>获得“<代码>”,而(定义(我的$Lay=)){…} /代码>考虑到,如果在循环中没有明确的<代码>定义的< /代码>或测试<代码> <代码>的返回,则有很多次误解了“0”值的合法读取。 以下是几个例子:

#!/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: $!";
}
#/usr/bin/perl
严格使用;使用警告;
my$str=join“”,映射{“$\n”}-10..10;
$str.=“0”;
我的$sep='='x 10;
我的($fh,$line);

打开$fh,'如果你想写防御代码,请使用a。这就是为什么我不会编辑某人回答的含义(我只修改明显的拼写错误)。如果您认为缺少或可以改进某些内容,请添加注释。感谢你对内部结构的调查!PS,我爱…绝对爱
在5.12及以上版本中的有效语法。我爱死它了。我想知道是否有人曾经被这种隐含的
定义的
?No-1咬过屁股,因为我同意
B::Deparse
在你被难倒时对探索Perl在做什么是有用的,但是我怎么用它来“回答”这样的问题不是。。。正确的。它只告诉您Perl在您尝试它的少数特定情况下会做什么,而没有告诉您发生这种行为的一般条件。只有语言规范才能告诉你这一点。@j_random_hacker,因为perl5没有正式的语言规范,解释器的行为是定义性的answer@j_random_hacker:在perl的辩护中,perl6结束了这一局面。有一个规范,有几个独立的实现可供比较。规范是最终的好答案,所以我删除了我的。但是Perl文档有误导性——它们说,“如果且仅当输入符号是while语句的条件内部的唯一内容”——但是后来与“且仅当”部分相矛盾,因为它显示
while(my$line=)
的行为也一样。L
#!/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: $!";
}