如果文件与模式匹配,则删除文件中的第一行

时间:2012-02-05 10:25:11

标签: algorithm perl pattern-matching

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

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
.
.
.

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

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

正如我所提到的,这使得工作完成了。但是,当知道文本只出现在第一行时,读取整个文件中的每一行似乎是浪费资源。

有没有办法更有效地完成这项任务?

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

提前致谢!

3 个答案:

答案 0 :(得分:3)

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

perl -i.bak -ne'print if $. != 1 || !/^Date/;' file
然而,在整个文件中读取每一行似乎浪费了很多资源

除了文件末尾之外的任何地方都无法删除。要从开头或中间删除,需要移动文件中后面的所有内容,这意味着必须同时读取和写入。

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

答案 1 :(得分: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;

答案 2 :(得分:1)

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

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;
    }
}