根据前一行的模式匹配修改下一行

时间:2014-03-09 09:27:45

标签: regex perl loops

我有一小段代码,通过在模式匹配的基础上在行前面插入#来为文件添加注释。我面临的挑战是将#添加到下一行。这是我到目前为止编写的代码:

#!/usr/bin/perl

use warnings;

open(FILE, "<extensions.txt") || die "File not found";
my @lines = <FILE>;
close(FILE);

my @newlines;
foreach(@lines) {
   $_ =~ s/\[google\.com/\#\[google\.com/g;
   push(@newlines,$_);
}

open(FILE, ">ext.txt") || die "File not found";
print FILE @newlines;
close(FILE);

因此,这会搜索以[google开头的任何行,并将其替换为#[google。我也要评论下一行。

这是一个示例文件:

[google.com]
Once upon a time...

[google.com-out-outnew]
Meanwhile, in the land of ...

[yahoo.com]
Centuries ago, the scion of ....

一旦我运行上面的脚本,我得到:

#[google.com]
Once upon a time...

#[google.com-out-outnew]
Meanwhile, in the land of ...

[yahoo.com]
Centuries ago, the scion of ....

以下是我正在寻找的输出示例:

#[google.com]
#Once upon a time...

#[google.com-out-outnew]
#Meanwhile, in the land of ...

[yahoo.com]
Centuries ago, the scion of ....

我知道它应该在这一行$_ =~ s/\[google\.com/\#\[google\.com/g;之后,但我感到困惑的是如何修改下一行,然后在循环中跳过它。有人可以解释一下这是怎么回事吗?

3 个答案:

答案 0 :(得分:3)

这是一个单行,可以(至少)两种方式完成:

> perl -pwe'$_ .= "#" . <> if s/(?=\Q[google.com\E)/#/g;' google.txt
#[google.com]
#Once upon a time...

#[google.com-out-outnew]
#Meanwhile, in the land of ...

[yahoo.com]
Centuries ago, the scion of ....

如果执行替换,则下一行<>将附加到当前行$_。替换只是lookahead assertionquotemeta escape \Q ... \E相结合,会在匹配的文本前插入#

一个小小的警告是,如果在文件的最后一行找到字符串,您将收到未初始化的警告,因为文件句柄将在eof处返回undef。另一个未处理的边缘情况是,如果你连续两行google,但我认为你的格式不允许。

处理此问题的另一种方法是使用段落模式,因为您的记录似乎是由双换行符(空行)分隔。

perl -00 -lpwe's/^/#/gm if /^\Q[google.com\E/' google.txt

请注意,这需要使用/m/g修饰符,这允许^分别匹配换行符和多个匹配项。 -00将输入记录分隔符更改为""\n\n的特殊情况),它会将整个记录读入$_-l开关将在替换前删除新的输入记录分隔符\n\n以避免额外的#,并在完成后替换它。

您可以将单行运行作为就地编辑,或将输出重定向到新文件

perl -pi.bak -we ' ...' yourfile.txt       # in-place edit with backup
perl -pwe ' ... ' yourfile.txt > new.txt   # redirect to new file

答案 1 :(得分:2)

只需设置一个等于是否找到模式的标志,然后打印前面带有'#'的行,如果是,则重置标志,然后跳到下一个循环迭代。

您可以查看s/// operator的结果,即替换次数。

这是根据现代Perl实践重写的代码,并进行了优化,因此您不需要数组。

#!/usr/bin/perl
use strict;

my $pattern_found;

open my $file_in, "<extensions.txt" or die $!;
open my $file_out, ">ext.txt" or die $!;

while (<$file_in>) {
   if ($pattern_found) {
       $pattern_found = 0;
       print $file_out "#$_";
       next
   }
   $pattern_found = $_ =~ s/\[google\.com/\#\[google\.com/g;
   print $file_out $_;
}

答案 2 :(得分:0)

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

my $srcfile = 'extensions.txt';
my $outfile = 'ext.txt';

open my $infh, '<', $srcfile;
open my $outfh, '>', $outfile;

my $comment_next_line = 0;

while (<$infh>) {
    if ($comment_next_line) {
        $comment_next_line = 0;
        s/^/#/;
    } elsif (s/(?=\[google\.com)/#/g) {
        $comment_next_line = 1;
    }

    $outfh->print($_);
}