当前文件行号为$.变量

Fre*_*sen 9 perl line-numbers text-files

我知道我可以获取我使用内置变量循环的文件的当前行号$..作为一个实验,我用它来为文件中的每一行添加前缀$.(当前行号)的值.但是,这没有按预期工作.即给出以下文件内容

line one
line two
line three
Run Code Online (Sandbox Code Playgroud)

那么我希望以下代码为每一行添加其行号前缀

for my $line (<FILE>) {
    print "$. : $line";
}
Run Code Online (Sandbox Code Playgroud)

但是,它给出了以下输出

3 line one
3 line two
3 line three
Run Code Online (Sandbox Code Playgroud)

在每行前面加上文件中的行数.而不是当前的线.

Mar*_*eed 17

那是因为你编写循环的方式是在循环遍历行之前读取整个文件.除非你有特殊的理由需要比简单的顺序访问文件更好的东西,你应该使用while而不是for像这样:

while (my $line = <FILE>) {
  print "$. : $line";
}
Run Code Online (Sandbox Code Playgroud)

当在列表上下文中调用< filehandle时 >(因为它在您的for循环中),它将作为行列表返回文件的全部内容.因此,您的代码行为与您编写代码的方式大致相同:

my @lines = <FILE>;            # now $. is set to the end of the file 
for my $line (@lines) { ... }  # you're just looping over an array, not touching $.
Run Code Online (Sandbox Code Playgroud)

为了达到理想的结果,你应该<>在标量上下文(while条件中的赋值)中重复调用,一次从文件中获取一行,并执行$.设置为正确数字的循环体.

此外,全局文件句柄被认为是不好的做法.出于几个原因,最好使用词法变量引用的文件句柄,如下所示:

open my $file, '<', $filename or die $!;
while (my $line = <$file>) {
  print "$. : $line";
}
Run Code Online (Sandbox Code Playgroud)

此外,由于$.是一个包含最近执行的读操作的行号的全局变量,如果在和之间发生另一次读取的可能性,则不应该依赖它.相反,请询问您用于行号的文件句柄:<$file>print

open my $file, '<', $filename or die $!;
while (my $line = <$file>) {
  print $file->input_line_number, " : $line";
}
Run Code Online (Sandbox Code Playgroud)

使用全局文件句柄,即使有点笨拙,它甚至可以工作:

while (my $line = <FILE>) {
  print ${\*FILE}->input_line_number, " : $line";
}
Run Code Online (Sandbox Code Playgroud)

...甚至是一个空的读取的默认值<>,实际命名为ARGV:

while (my $line = <>) {
  print ${\*ARGV}->input_line_number, " : $line";
}
Run Code Online (Sandbox Code Playgroud)

  • 好答案.请注意,在该上下文中不需要检查`defined` - Perl会自动执行此操作.在文档中找不到这个位置,但是这个例子显示了它:`perl -MO = Deparse -e"while(my $ line = <$ fh>){print}"`. (4认同)
  • @ user2676699我认为这不是重点.相反,关键是Perl会为您插入对`defined()`的调用.请参阅我发布的代码的输出,以及:http://perldoc.perl.org/perlop.html#I%2fO-Operators. (2认同)
  • 如果任何中间代码执行自己的`<$ fh>`代码,那么`$ .`在`<$ fh>`和`print`之间会有变化的风险,因为`$ .`总是指的是最近读取的文件句柄的行号,并不是词法.如果你想避免这种情况,请使用`IO :: Handles`` $ fh-> input_line_number` (2认同)