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

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

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

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

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

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

Ответы [ 9 ]

23 голосов
/ 25 июня 2009

Вы хотите что-то вроде этого:

my @grabbed;
while (<FILE>) {
    if (/TARGET/) {
        push @grabbed, $_;
        while (<FILE>) {
            last if /^$/;
            push @grabbed, $_;
        }
    }
}
14 голосов
/ 25 июня 2009

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

$ 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
10 голосов
/ 25 июня 2009

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

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

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

4 голосов
/ 31 июля 2009

От ответа 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 $.
}
2 голосов
/ 25 июня 2009
while(<FILE>)
{
    if (/target/i)
    {
        $buffer .= $_;
        while(<FILE>)
        {
            $buffer .= $_;
            last if /^\n$/;
        }
    }
}
1 голос
/ 25 июня 2009
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

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

0 голосов
/ 28 марта 2016
while (<IN>) {
print OUT if (/Target/../^$/) ; 
}   
0 голосов
/ 25 июня 2009

Если вам нужен только один цикл (изменение кода Дэйва Хинтона):

my @grabbed;
my $grabbing = 0;
while (<FILE>) {
    if (/TARGET/ ) {
       $grabbing = 1;
    } elsif( /^$/ ) {
       $grabbing = 0;
    }
    if ($grabbing) {
        push @grabbed, @_;
    }
}
0 голосов
/ 25 июня 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...