Пропуск или исключение совпадений регулярных выражений из сценария Perl - PullRequest
1 голос
/ 26 ноября 2009

Привет, я хочу найти что-то в файле, который выглядит примерно так:

Start Cycle
report 1
report 2
report 3
report 4
End Cycle

.... продолжается и продолжается ..

Я хочу найти «Начать цикл», а затем извлечь отчет 1 и отчет 3 из него. Мое регулярное выражение выглядит примерно так

(Start Cycle .*\n)(.*\n)(.*\n)(.*\n)

Приведенное выше регулярное выражение выбирает цикл запуска и следующие три строки. Но я хочу опустить третью строку в моем результате. Это возможно? Или любой более простой скрипт на Perl можно сделать ?? Я ожидаю такой результат, как:

Start Cycle
report 1
report 3

Ответы [ 8 ]

5 голосов
/ 26 ноября 2009

Следующий код печатает нечетные строки между Start Cycle и End Cycle:

foreach (<$filehandle>) {
    if (/Start Cycle/ .. /End Cycle/) {
        print if /report (\d+)/ and $1 % 2;
    }
}
2 голосов
/ 26 ноября 2009

Возможно, сумасшедший способ сделать это: изменить понимание Perl входной записи.

$/ = "End Cycle\n";
print( (/(.+\n)/g)[0,1,3] ) while <$file_handle>;
2 голосов
/ 26 ноября 2009

Вы можете найти текст между начальным и конечным маркерами, а затем разделить контекст по строкам. Вот пример:

my $text = <<TEXT;
Start Cycle
report 1
report 2
report 3
report 4
End Cycle
TEXT

## find text between all start/end pairs
while ($text =~ m/^Start Cycle$(.*?)^End Cycle$/msg) {
    my $reports_text = $1;
    ## remove leading spaces
    $reports_text =~ s/^\s+//;
    ## split text by newlines
    my @report_parts = split(/\r?\n/m, $reports_text);
}
1 голос
/ 26 ноября 2009

Я взял вопрос ОП в качестве упражнения на Perl и придумал следующий код. Это было просто написано в учебных целях. Пожалуйста, поправьте меня, если что-то выглядит подозрительно.

while(<>) {
   if(/Start Cycle/) {
        push @block,$_;
        push @block, scalar<> for 1..3;               
        print @block[0,1,3];
        @block=(); 
           }
        }

Другая версия (отредактировано и спасибо, @ FM):

local $/;
$_ = <>;
  @block = (/(Start Cycle\n)(.+\n).+\n(.+\n)/g);
  print @block;
1 голос
/ 26 ноября 2009

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

(Start Cycle .*\n)(.*\n).*\n(.*\n)
1 голос
/ 26 ноября 2009

Регулярное выражение заполняет $ 1, $ 2, $ 3 и $ 4 содержимым каждой пары скобок.

Так что, если вы просто посмотрите на содержимое $ 1, $ 2 и $ 4, у вас есть то, что вы хотите.

В качестве альтернативы вы можете просто снять скобки с третьей строки.

Ваше регулярное выражение должно выглядеть примерно так:

/Start Cycle\n(.+)\n.+\n(.+)\n.+\nEnd Cycle/g

/ g позволит вам повторно оценить регулярное выражение и всегда получать следующий матч каждый раз.

0 голосов
/ 26 ноября 2009
while (<>) {
    if (/Start Cycle/) {
        print $_;
        $_ = <>;
        print $_;
        $_ = <>; $_ = <>;
        print $_;
    }
}
0 голосов
/ 26 ноября 2009

Обновление: Изначально я не заметил, что это был просто @ ответ FM в несколько более надежной и длинной форме.

#!/usr/bin/perl

use strict; use warnings;

{
    local $/ = "End Cycle\n";
    while ( my $block = <DATA> ) {
        last unless my ($heading) = $block =~ /^(Start Cycle\n)/g;
        print $heading, ($block =~ /([^\n]+\n)/g)[1, 3];
    }
}

__DATA__
Start Cycle
report 1
report 2
report 3
report 4
End Cycle

Выход:

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