【问题标题】:Delete first line in file if it matches a pattern如果匹配模式,则删除文件中的第一行
【发布时间】:2012-02-05 10:25:11
【问题描述】:

我想知道如果文件中的第一行匹配指定的模式,是否有一种有效的方法来删除它。例如,我有一个包含以下形式数据的文件:

Date,Open,High,Low,Close,Volume,Adj.Volume
2012-01-27,42.38,42.95,42.27,42.68,2428000,42.68
2012-01-26,44.27,44.85,42.48,42.66,5785700,42.66
.
.
.

我想删除第一行,前提是它包含文本(如第一行的示例所示),如果它只包含数字(如其余行),则保持不变。这个任务非常简单,我通过应用以下代码和平来完成它,只要它不包含Date 模式,它将每一行写入$newFile

while( <$origFile> )
    {
        chomp($_);
        print $newFile $_ unless ($_  =~ m/Date/g)
    }

正如我所提到的,这使工作完成。然而,当已知文本只能出现在第一行时,读取整个文件中的每一行似乎是一种极大的资源浪费..

有什么方法可以更有效地完成这项任务吗?

注意:我已经找到了一个几乎类似的问题 here,但由于我希望我的代码也可以在 Linux 和 Windows 上使用,所以在这里使用 sed 对我没有帮助。

提前致谢!

【问题讨论】:

  • 无论在文件中的位置如何,您的代码都会删除这行文本。至于效率低下:您必须读取文件中的所有行,您不能从文件的开头删除字节(这就是文件系统的工作方式)。注意:您将在Perl: How do I remove the first line of a file without reading and copying whole file 中找到答案——只需与您的正则表达式结合即可。
  • (1) 您不想在不添加换行符的情况下大吃一惊,因为这会将您的整个输入文件放在一行上! (2) 你不需要指定 "$_ =~" 因为 m// 默认对 $_ 起作用。 (3) 您不需要 m// 上的 'g' 标志;它在这里什么也没做。

标签: algorithm perl pattern-matching


【解决方案1】:

$. 可用于确定是否正在处理文件的第一行。

perl -i.bak -ne'print if $. != 1 || !/^Date/;' file
但是读取整个文件中的每一行似乎是一种极大的资源浪费

除了文件末尾之外,不可能从任何地方删除。要从开头或中间删除,文件中的所有内容都需要移位,这意味着它必须是可读写的。

只有当第一行不匹配时,你才能避免工作(什么都不做)。如果需要删除该行,则必须复制整个文件。

【讨论】:

    【解决方案2】:

    Tie::File 模块非常适合这种情况。它非常高效,因为它会阻塞 IO 而不是一次读取一行,而且它使程序编写起来非常简单。

    use strict;
    use warnings;
    
    use Tie::File;
    
    tie my @data, 'Tie::File', 'mydatafile' or die $!;
    shift @data if $data[0] =~ /Date/;
    untie @data;
    

    【讨论】:

      【解决方案3】:

      只在第一行进行测试,然后直接运行文件的其余部分而不检查:

      if (defined( $_ = <$origFile> )) {
          if ( ! m/Date/o ) { print $newFile $_ }
      
          my $data;
      
          for (;;) {
              my $readRes = read($origFile, $data, 0x10000);
      
              if (!defined $readRes) { die "Can't read: $!" }
      
              if ($readRes == 0) { last }
      
              print $newFile $data;
          }
      }
      

      【讨论】:

      • 您好,感谢您的回复!但是我不确定我是否完全理解你的代码......你能否提供一些解释,特别是for (;;)read 参数。谢谢!
      • for (;;)while (1) 的简写,即不指定退出条件的循环(我们在中间使用last 退出循环)。内置函数 read 记录在 perldoc.perl.org/functions/read.html
      最近更新 更多