当找到匹配项时,如何打印上一行和下一行空行之间的所有行?

时间:2009-10-10 03:47:47

标签: perl

我绞尽脑汁试图找到一个解决方案但是徒劳无功。任何指导将不胜感激。

_data_
mascot
friend
ocean
\n
parsimon
**QUERY**
apple
\n
jujube
\n
apricot
maple
**QUERY**
rose
mahonia
\n

....鉴于搜索关键字是 QUERY ,它会输出:

parsimon
**QUERY**
apple

apricot
maple
**QUERY**
rose
mahonia

我编写的代码无法正常工作:

#!/usr/bin/perl

use strict; 
use warnings;

open my $fh, '<', 'FILE' or die "Cannot open: $!";
my @file = <$fh>;
close $fh;

for (0 .. $#file) {   # read from the first line to the last
  if($file[$_] =~ /QUERY/){  # if the contents of a particular line matches the query pattern
        my $start = $_-- until $file[$_--] =~ /^$/; #check the previous line for an empty line. continue until success. store the index of the empty line to $start.
        my $end = $_++ until $file[$_++] =~ /^$/; #check the next line for an empty line. continue until sucess. store the index of the empty line to $end.

print "\n @file[$start..$end]"; #print all lines between the stored indexes
}
}

我也尝试了类似的东西,但有句法错误:

if($file[$_] =~ /QUERY/){
        my $start = $_-4 if $file[$_-4] =~ /^$/;
      continue  my $start = $_-3 if $file[$_-3]=~/^$/;
  ------
my $end = $_+4 until $file[$_+4] =~ /^$/;
.....

print "\n @file[$start..$end]";
}
.....

似乎我迄今为止成功实现的唯一好处是我可以使用以下代码在匹配行和下一行空行之间打印所有内容:

for (0 .. $#file) {
  if($file[$_+1] =~ /QUERY/) {
   print $file[$_] until $file[$_++]=~/^$/;

有人能指出我正确的方向吗? 谢谢!

麦克

修改

我认为brian d foy解决我的问题是最好的。我认为最有效率。但杰夫的解决方案是最有帮助的,我特别从他详细的逐行解释中得到了很多好处,甚至更好,使用他的代码,只做了一些调整,我可以做其他事情,例如,打印之间的所有行找到模式时以数字开头的行。而Kinopiko的代码是我希望能够编写的代码。

4 个答案:

答案 0 :(得分:7)

哇,你们真的很喜欢在这些答案中做很多工作。请记住,在文本处理中,Perl使简单的事情变得容易(并且可能很难)。如果你为很容易解释的事情做了很多工作,你可能会错过这么简单的方法。 :)

只需将一行重新定义为一个段落,并在阅读时打印匹配的段落。您可以通过将输入记录分隔符$/设置为所需的行结尾来更改Perl对行的概念。当您使用行输入操作符时,您将获得所有内容,包括$/中的内容。有关Perl特殊变量的详细信息,请参阅perlvar

#!perl

{
    local $/ = "\n\n";

    while( my $group = <DATA> ) {
        print $group if $group =~ /\Q**QUERY**/;
    }
 }


__DATA__
mascot
friend
ocean

parsimon
**QUERY**
apple

jujube

apricot
maple
**QUERY**
rose
mahonia

ghostdog74发布了他的单行版本,我稍作修改:

perl -ne "$/=qq(\n\n); print if /\Q**QUERY**/" fileA fileB ...
不过,

perl有一个特殊的命令行开关。您使用-0设置输入记录分隔符,如果将其设置为0,则表示您将其设置为使用段落模式:

perl -00 -ne "print if /\Q**QUERY**/" fileA fileB ...

perlrun向您展示了您可以在命令行上执行的所有精彩内容。

答案 1 :(得分:2)

# more file
mascot
friend
ocean

parsimon
**QUERY**
apple

jujube

apricot
maple
**QUERY**
rose
mahonia

# perl -ne '$/ = "\n\n";print $_ if /QUERY/' file
    parsimon
    **QUERY**
    apple

    apricot
    maple
    **QUERY**
    rose
    mahonia

答案 2 :(得分:1)

这里有一些“吼叫者”。

  • 您正在使用$ _作为循环变量的循环中修改$ _。
  • 你是双倍减少,也是双倍增加$ _。
  • 您似乎没有处理文件的顶部和底部。

这似乎有效:

我的@file =&lt; DATA&gt;

for (0 .. $#file) {
    if ($file[$_] =~ /QUERY/){
 my $start = $_;
 while ($start >= 0 && $file[$start] !~ /^$/) {
     $start--;
 }
        my $end = $_;
 while ($end <= $#file && $file[$end] !~ /^$/) {
     $end++;
 }
 print "\n@file[$start+1..$end-1]";
    }
}
__DATA__
mascot
friend
ocean 
parsimon
QUERY
apple 

jujube 
apricot
maple
QUERY
rose
mahonia 

答案 3 :(得分:1)

这会产生您指定的输出,假设您的意思是“如果找到QUERY,则返回从前一个空白行到下一个空行的所有内容”。如果文件末尾没有空行,则在最后一种情况下会失败,但您可以在while循环后检查最后一个候选项。

#!/usr/bin/perl

use strict;
use warnings;

# Open the file
open my $fh, '<', 'FILE' or die "Cannot open: $!";

# initialize the candidate to an empty string
# This is good form, so we know that we are starting with an empty candidate.
my $candidate = '';

# Go through each line of the file
# The contents of the line will be placed in $_
while(<$fh>) {

    # If the line is blank, check the candidate we have accumulated
    # This is shorthand for 'if($_ =~ /^$/) {'
    if(/^$/) {

        # If the candidate contains your QUERY, print it out
        # Alternately, you could add it to an array, etc
     if($candidate =~ /\nQUERY\n/) {
            print "$candidate\n";
        }

        # We are done with the previous candidate, so clear it out
        $candidate = '';
    } else {

        # If it is not a blank line, concatenate it to your
        # candidate.  I.e. build up all of the lines between blanks
        $candidate .= $_;
    }
}

# This handles the final lines, if there is not a blank line
# at the end of the file
if($candidate =~ /\nQUERY\n/) {
    print "$candidate\n";
}