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

Это не специальный оператор, это два стандартных оператора один за другим:

  1. Декремент префикса (--)
  2. Логическое не (!)

Это приводит к тому, что значение pending уменьшается, а затем проверяется на нулевое значение.

11
задан brian d foy 25 June 2009 в 15:50
поделиться

8 ответов

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

my @grabbed;
while (<FILE>) {
    if (/TARGET/) {
        push @grabbed, $_;
        while (<FILE>) {
            last if /^$/;
            push @grabbed, $_;
        }
    }
}
23
ответ дан 3 December 2019 в 00:53
поделиться

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

$ 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
14
ответ дан 3 December 2019 в 00:53
поделиться

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

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

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

10
ответ дан 3 December 2019 в 00:53
поделиться
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

Отредактируйте, чтобы исправить условие выхода в соответствии с примечанием ниже.

1
ответ дан 3 December 2019 в 00:53
поделиться
while(<FILE>)
{
    if (/target/i)
    {
        $buffer .= $_;
        while(<FILE>)
        {
            $buffer .= $_;
            last if /^\n$/;
        }
    }
}
2
ответ дан 3 December 2019 в 00:53
поделиться

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

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

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

0
ответ дан 3 December 2019 в 00:53
поделиться

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

my @grabbed;
my $grabbing = 0;
while (<FILE>) {
    if (/TARGET/ ) {
       $grabbing = 1;
    } elsif( /^$/ ) {
       $grabbing = 0;
    }
    if ($grabbing) {
        push @grabbed, @_;
    }
}
0
ответ дан 3 December 2019 в 00:53
поделиться

From perlfaq6's answer to How can I pull out lines between two patterns that are themselves on different lines?


You can use Perl's somewhat exotic .. operator (documented in perlop):

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

If you wanted text and not lines, you would use

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

But if you want nested occurrences of START through END, you'll run up against the problem described in the question in this section on matching balanced text.

Here's another example of using ..:

while (<>) {
    $in_header =   1  .. /^$/;
    $in_body   = /^$/ .. eof;
# now choose between them
} continue {
    $. = 0 if eof;  # fix $.
}
4
ответ дан 3 December 2019 в 00:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: