Как я могу получить несколько строк после совпадающей строки в Perl?

Я построчно анализирую большой файл в Perl (завершается \ n), но когда я достигаю определенного ключевого слова, скажем «TARGET», мне нужно перехватить все строки между TARGET и следующей полностью пустой строкой ,

Итак, учитывая сегмент файла:

Строка 1
Линия 2
Линия 3
Линия 4 Цель
Строка 5 Захватите эту строку
Строка 6 Захватите эту строку
\ п

Это должно стать:
Линия 4 Цель
Строка 5 Захватите эту строку
Строка 6 Захватите эту строку

Причина, по которой у меня возникают проблемы, заключается в том, что я уже перебираю файл построчно; Как мне изменить то, что я делим в середине процесса разбора?

Ответы на вопрос(9)

Ты хочешь что-то вроде этого:

my @grabbed;
while (<FILE>) {
    if (/TARGET/) {
        push @grabbed, $_;
        while (<FILE>) {
            last if /^$/;
            push @grabbed, $_;
        }
    }
}

The Оператор идеально подходит для такого рода задач:

$ cat try
#! /usr/bin/perl

while (<DATA>) {
  print if /\btarget\b/i .. /^\s*$/
}

__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Nope
Line 7 Target
Linu 8 Yep

Nope again

$ ./try
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Line 7 Target
Linu 8 Yep

кода, и при условии, что вы просто хотите строки междуTARGET и следующую пустую строку и хотите, чтобы все остальные строки были отброшены, вы можете использовать вывод этой команды:

s2p -ne '/TARGET/,/^$/p'

(Да, это намек на то, что эту проблему обычно легче решить вsed. :-П

while(<FILE>)
{
    if (/target/i)
    {
        $buffer .= $_;
        while(<FILE>)
        {
            $buffer .= $_;
            last if /^\n$/;
        }
    }
}
use strict;
use warnings;

my $inside = 0;
my $data = '';
while (<DATA>) {
    $inside = 1 if /Target/;
    last if /^$/ and $inside;
    $data .= $_ if $inside;
}

print '[' . $data . ']';

__DATA__
Line 1
Line 2
Line 3
Line 4 Target
Line 5 Grab this line
Line 6 Grab this line

Next Line

чтобы исправить условие выхода согласно примечанию ниже.

$/, поэтому, когда вы нажмете TARGET, вы можете установить$/ в"\n\n", прочитайте следующую «строку», а затем установите ее на «\ n» ... et voilà!

Теперь для более длинного: если вы используетеEnglishодуль @ (который дает разумные имена всем магическим переменным Perl, затем$/ называется$RS или$INPUT_RECORD_SEPARATOR. Если вы используетеIO::Handle, тогдаIO::Handle->input_record_separator( "\n\n") буду работать

И если вы делаете это как часть большого кода, не забудьте либо локализовать (используяlocal $/; в соответствующем объеме) или для возврата$/ к исходному значению"\n".

Perlfaq6 ответ Как я могу вытянуть линии между двумя шаблонами, которые сами по себе находятся на разных линиях?

Вы можете использовать несколько экзотический оператор Perl .. (задокументировано в perlop):

perl -ne 'print if /START/ .. /END/' file1 file2 ...

Если бы вы хотели текст, а не строки, вы бы использовали

perl -0777 -ne 'print "$1\n" while /START(.*?)END/gs' file1 file2 ...

Но если вы хотите использовать вложенные вхождения START через END, вы столкнетесь с проблемой, описанной в вопросе в этом разделе о сопоставлении сбалансированного текста.

Вот еще один пример использования ..:

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}

my @grabbed;
my $grabbing = 0;
while (<FILE>) {
    if (/TARGET/ ) {
       $grabbing = 1;
    } elsif( /^$/ ) {
       $grabbing = 0;
    }
    if ($grabbing) {
        push @grabbed, @_;
    }
}
while (<IN>) {
print OUT if (/Target/../^$/) ; 
}   

ВАШ ОТВЕТ НА ВОПРОС