【问题标题】:Perl problems printing output to a new filePerl 将输出打印到新文件时出现问题
【发布时间】:2011-09-02 19:28:34
【问题描述】:

我想删除文本文件中以 HPL_ 开头的所有行新文件。请帮忙!

open(FILE,"<myfile.txt"); 
@LINES = <FILE>; 
close(FILE); 
open(FILE,">myfile.txt"); 
foreach $LINE (@LINES) { 
@array = split(/\:/,$LINE); 


my $file = "changed";

open OUTFILE, ">$file" or die "unable to open $file $!";

print OUTFILE $LINE unless ($array[0] eq "HPL_");

} 
close(FILE); 
close (OUTFILE);




exit;

【问题讨论】:

  • 没有人愿意也不应该必须调试顶部没有use strict; use warnings 的Perl 代码。甚至尝试都是纯粹的疯狂。在现代 Perl 编程环境中,您还希望使用 use v5.12 或诸如此类来识别您正在运行的 Perl 版本,并且如果您是 5.10.1 或更高版本,还需要 use autodie。否则太难了。

标签: perl


【解决方案1】:

您只想删除所有以HPL_ 开头的行吗?这很简单!

perl -pi -e 's/^HPL_.*//s' myfile.txt

是的,它确实只是一条线。 :-)

【讨论】:

  • 好答案,我投了赞成票,但我也敢打赌,这只是整个问题的一部分,实际问题更复杂。换句话说,您可能已经回答了问题,但不是真正的需要。不批评;只是猜测。
  • 嗯,好的,这比我想象的要容易得多!谢谢:-)
  • 不会在HPL_ 以前的位置留下空白行吗?当我尝试它时,我必须显式添加\n 以删除空白行。
【解决方案2】:

如果你不想使用单行,重写“写入文件”部分如下:

my $file = "changed";
open( my $outfh, '>', $file ) or die "Could not open file $file: $!\n";
foreach my $LINE (@LINES) { 
  my @array = split(/:/,$LINE);
  next if $array[0] eq 'HPL_';
  print $outfh $LINE;
}
close( $outfh );

请注意您每次通过循环时如何open()ing 文件。这导致文件只包含最后一行,因为使用 open()&gt; 意味着“覆盖文件中的内容”。这是您的代码存在的主要问题。

编辑:顺便说一句,你想清理你的代码。如我所示,使用词法文件句柄。始终在每个 Perl 程序的顶部添加 tchrist 发布的三行代码。使用open() 的三运算符版本。不要将整个文件放入一个数组中,就好像您尝试读取一个巨大的文件可能会导致您的计算机内存不足一样。你的程序可以重写为:

#!perl

use strict;
use autodie; 
use warnings FATAL => "all";

my $infile = "myfile.txt";
my $outfile = "changed.txt";

open( my $infh, '<', $infile );
open( my $outfh, '>', $outfile );
while( my $line = <$infh> ) {
    next if $line =~ /^HPL_/;
    print $outfh $line;
}
close( $outfh );
close( $infh );

注意使用use autodie,您无需将or die ... 添加到open() 函数,因为autodie pragma 会为您处理。

【讨论】:

  • 很确定在打印中使用词法文件句柄需要将它们包装在 { 和 } 中。
  • @Rob:不,他们没有。也许在非常古老的 Perl 版本中,但至少从 5.6 天开始就没有了。只有在将文件句柄存储在数组中之类的操作时,您才需要这样做,在这种情况下,您必须执行 print { $fhs[1] } $line 之类的操作。另请参阅perldoc print
  • @CanSpice 啊。好吧,这表明我已经使用 Perl 多长时间了。 :)
  • @Rob 与格槽必须是⑴像STDOUTIO::Handle这样的裸词; ⑵ 一个标量变量,如$fh$His::fh; ⑶ 大括号分隔的块,如{ $Handles{$name} }{ get_handle() }{ $ok ? STDOUT : STDERR }。这与某个持有间接句柄的变量是否应该碰巧在词法范围内有关,也与它是否被自动激活无关。它一直,一直都是这样工作的。当你不是那个意思时,你们永远错误地说“词法文件句柄”,这会导致混淆。 句柄自动生存与词法作用域正交!
  • 例如,这些 词法文件句柄但不是自动激活的:my $fh = local *FOOmy $fh = *STDOUT{IO}my $fh = "main::STDOUT";。而且这个 不是 词法文件句柄,而是太自动了:open($His::fh=undef, "&lt; /dev/null"); print $His::fh "stuff\n"。而$His::fh = new IO::Handle:: 既不是词汇也不是自动生存。当你真正的意思是 autovivved 句柄时,你们都一直在说词法文件句柄,但这些是完全不同的概念。
【解决方案3】:

您的代码的问题是您在行处理循环中打开文件以进行输出,由于您使用“>”形式的打开,因此每次都打开文件以进行写入,从而消除任何先前的内容。

将 open() 的调用移动到文件顶部,循环上方,它应该可以工作。

另外,我不确定您的意图,但在示例的第 4 行,您重新打开输入文件以进行写入(使用“>”),这也会破坏其中包含的任何内容。

作为旁注,您可以尝试阅读 Perl 的 grep() 命令,该命令旨在完全满足您的需求,如下所示:

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

open(my $in, '<', 'myfile.txt') or die "failed to open input for read: $!";
my @lines = <$in> or die 'no lines to read from input';
close($in);

# collect all lines that do not begin with HPL_ into @result
my @result = grep ! /^HPL_/, @lines; 

open(my $out, '>', 'changed.txt') or die "failed to open output for write: $!";
print { $out } @result;
close($out);

【讨论】:

  • 没错,文件被循环中的每个 open() 覆盖。前两个打开很好,因为文件在关闭和重新打开之前已经加载到数组中。请注意,以“追加”模式打开文件并避免覆盖其内容是打开“>>$file”。 (在这个例子中不是一个好主意)
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-19
  • 2014-07-22
  • 2022-11-26
  • 2014-10-28
  • 2012-09-30
  • 1970-01-01
相关资源
最近更新 更多