Как я могу напечатать все строки между предыдущей и следующей пустой строкой, когда совпадение найдено? - PullRequest
0 голосов
/ 10 октября 2009

Я ломал голову, пытаясь найти решение, но тщетно. Любое руководство будет оценено.

_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[$_++]=~/^$/;

Может ли кто-нибудь указать мне правильное направление? Спасибо!

Mike

Редактировать

Я думаю, что решение моей проблемы Брайана Д Фоя - лучшее. Под лучшим я подразумеваю самый эффективный. Но решение Джеффа является наиболее полезным, и я очень выигрываю, особенно от его подробных построчных объяснений, и, что еще лучше, используя его код, используя всего несколько настроек, я могу сделать что-то еще, например, напечатать все строки между строки, начинающиеся с цифры, когда образец найден. А код Кинопико - это тот самый код, который я надеялся написать.

Ответы [ 4 ]

7 голосов
/ 10 октября 2009

Ого, ребята, вам действительно нравится много работать над этими ответами. Помните, что при обработке текста Perl упрощает простые вещи (и сложные). Если вы делаете много работы для чего-то, что легко объяснить, вы, вероятно, упускаете легкий путь. :)

Просто переопределите строку в качестве абзаца и напечатайте соответствующие абзацы по мере их чтения. Вы можете изменить представление Perl о строке, установив в качестве разделителя входной записи $/ желаемый конец строки. Когда вы используете оператор линейного ввода, вы получите обратно все, включая то, что находится в $/. Смотрите perlvar для подробностей о специальных переменных Perl:

#!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 показывает вам все изящные вещи, которые вы можете сделать в командной строке.

2 голосов
/ 10 октября 2009
# 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
1 голос
/ 10 октября 2009

Это приводит к тому, что вы указали вывод, предполагая, что вы имеете в виду «если найден 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";
}
1 голос
/ 10 октября 2009

Здесь есть несколько "ревунов".

  • Вы изменяете $ _ внутри цикла, который использует $ _ в качестве переменной цикла.
  • Вы вдвое уменьшаете, а также вдвое увеличиваете $ _.
  • Похоже, вы не имеете дело с верхом и низом файла.

Кажется, это работает:

my @file =

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...