我该如何在Perl中打印匹配行和接下来的三行?

3

我需要搜索一个模式并将该行和接下来的3行写入文件(FILE)中。这种方法正确吗?谢谢。

print FILE if /^abc/;
$n=3 if /^abc/;
print FILE if ($n-- > 0);

1
我花了一分钟才意识到你的 "--" 是 $n-- 和一个数字比较。 :) - brian d foy
6个回答

7

我喜欢..操作符:

perl -ne 'print if (/abc/ and $n=3) .. not $n--'

但是你没有描述如果以下三行重复出现abc模式会发生什么。如果你想重新开始计数,你的方法是正确的,只需要修复一下双打印的小错误即可。

perl -ne'$n=4 if/abc/;print if$n-->0'

你如何将其反转以打印前三行? - hwnd
你需要为三行创建一些缓冲区(例如环形缓冲区),如果找到模式,则打印此缓冲区。 - Hynek -Pichi- Vychodil

5
这是命令行grep(1)的一个功能。无需编程:
grep abc --after-context=3

你在每一组上下文之间会得到“--”行,但这些很容易去掉。用Perl做整个事情也很容易。 :)
关键是当以下三行中的一行也包含你正在寻找的模式时,你想要做什么。grep(1)会重置计数器并继续打印行。

这是GNU grep的一个特性 - 而不是POSIX grep的特性。 - Jonathan Leffler

5
你可以简化它,使用一个标志变量来判断是否应该打印一行:
while( <$input> ) {
    $n=4 if /^abc/; 
    print FILE if ($n-- > 0);
    }

除了简化之外,它还修复了一个问题:在您的版本中,abc字符串将被打印两次。

不,我的意思是如果,这里不需要while。 - Igor Krivokon
@Igor 好的,这两行代码应该在一个 while 循环内。然而,$n 会在每次循环中递减。如果在以 abc 开头的行之间有足够多的行,它可能会绕回来。 - Sinan Ünür

2

不需要一次性读入文件或试图将代码写在单行中:

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

while ( my $line = <DATA> ) {
    if ( $line =~ /^abc/ ) {
        print $line;
        print scalar <DATA> for 1 .. 3;
    }
}
__DATA__
x
y
z
abc
1
2
3
4
5
6

2
这里有一个bug,给定文件 "abc\nabc\n1\n2\n\n",你会打印前四行,但不包括第五行。 - Chas. Owens

0

另一个可能的解决方案...

#!/usr/bin/perl

use strict;

my $count = 0;
while (<DATA>) {
    $count = 1 if /abc/;
    if ($count >= 1 and $count <= 3) {
        next if /abc/;
        print;
        $count++;
    }
}

__DATA__
test
alpha
abc
1
234123
new_Data
test

-3

我宁愿多写几行代码,让所有东西更加清晰。像这样的代码应该可以工作:

my $count = 0;
while ( my $line = pop @file ) {
   if ( /^abc/ ) {
      $count = 4;
   }

   if ( $count > 0 ) {
       print FILE $line;
       $count--;
   }
}

编辑以回应评论:

  • 缺少正则表达式是一个错误,现在已经修复。
  • 打印换行符与否当然是可选的,读入文件也是如此。不同的人有不同的风格,这就是人们喜欢 Perl 的其中之一的原因!

两个小潜在问题:你可能不需要插入“\n”。另外,如果abc后面的3行中有一行包含abc,你会错过它。 - Igor Krivokon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接