Как извлечь строки между двумя разделителями строк в Perl?

StackOverflow https://stackoverflow.com/questions/1212799

Вопрос

У меня есть файл журнала ASCII с некоторым содержимым, которое я хотел бы извлечь. Я никогда не тратил время на изучение Perl, но думаю, что это хороший инструмент для этой задачи.

Файл структурирован следующим образом:

... 
... some garbage 
... 
... garbage START
what i want is 
on different
lines 
END 
... 
... more garbage ...
next one START 
more stuff I want, again
spread 
through 
multiple lines 
END 
...
more garbage

Итак, я ищу способ извлечь строки между каждой строкой разделителя START и END . Как я могу это сделать?

Пока что я нашел только несколько примеров того, как напечатать строку со строкой START или другие элементы документации, которые в некоторой степени связаны с тем, что я ищу.

Это было полезно?

Решение

Требуется оператор триггера (более известный как оператор диапазона) ..

#!/usr/bin/env perl
use strict;
use warnings;

while (<>) {
  if (/START/../END/) {
    next if /START/ || /END/;
    print;
  }
}

Замените вызов print тем, что вы на самом деле хотите сделать (например, вставьте строку в массив, отредактируйте ее, отформатируйте и т. д.). Я следующий перебиваю строки, которые на самом деле имеют START или END , но вы можете не захотеть этого поведения. См. эту статью для обсуждения этого оператора и других полезные специальные переменные Perl.

Другие советы

Из 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 $.
}

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

Как это? В этом случае строка END равна $ ^, вы можете изменить ее на свою строку END.

Я тоже новичок, но решения там предоставляют немало методов ... дайте мне знать, что именно вы хотите, что отличается от приведенной выше ссылки.

while (<>) {
    chomp;      # strip record separator
    if(/END/) { $f=0;}
    if (/START/) {
        s/.*START//g;
        $f=1;
    }
    print <*>

попробуйте написать код в следующий раз

."\n" if $f; }

попробуйте написать код в следующий раз

После ответа Телемаха все стало течь. Это работает как решение, которое я смотрю в конце концов.

<Ол>
  • Я пытаюсь извлечь строки, разделенные двумя строками (одна со строкой, оканчивающейся на "CINFILE ="; другая, со строкой, содержащей один " # "), в отдельных строках, исключая разделитель линий. Это я могу сделать с помощью решения Telemachus.
  • В первой строке есть пробел, который я хочу удалить. Я тоже это включаю.
  • Я также пытаюсь извлечь каждый набор строк в отдельные файлы.
  • Это работает для меня, хотя код можно классифицировать как некрасивый; это потому что я в настоящее время практически новичок в Perl. В любом случае здесь идет:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    
    my $start='CINFILE=
    
    

    Я надеюсь, что это принесет пользу и другим. Приветствия.

    ; my $stop='^#

    Я надеюсь, что это принесет пользу и другим. Приветствия.

    ; my $filename; my $output; my $counter=1; my $found=0; while (<>) { if (/$start/../$stop/) { $filename=sprintf("boletim_%06d.log",$counter); open($output,'>>'.$filename) or die $!; next if /$start/ || /$stop/; if($found == 0) { print $output (split(/ /))[1]; } else { print $output

    После ответа Телемаха все стало течь. Это работает как решение, которое я смотрю в конце концов.

    <Ол>
  • Я пытаюсь извлечь строки, разделенные двумя строками (одна со строкой, оканчивающейся на "CINFILE ="; другая, со строкой, содержащей один " # "), в отдельных строках, исключая разделитель линий. Это я могу сделать с помощью решения Telemachus.
  • В первой строке есть пробел, который я хочу удалить. Я тоже это включаю.
  • Я также пытаюсь извлечь каждый набор строк в отдельные файлы.
  • Это работает для меня, хотя код можно классифицировать как некрасивый; это потому что я в настоящее время практически новичок в Perl. В любом случае здесь идет:

    <*>

    Я надеюсь, что это принесет пользу и другим. Приветствия.

    ; } $found=1; } else { if($found == 1) { close($output); $counter++; $found=0; } } }

    Я надеюсь, что это принесет пользу и другим. Приветствия.

    Неплохо для того, чтобы прийти от «виртуального новичка». Одна вещь, которую вы могли бы сделать, - это поместить " $ found = 1 " внутри " if ($ found == 0) " блокировать, чтобы вы не делали это назначение каждый раз между $ start и $ stop.

    Еще одна вещь, которая, на мой взгляд, несколько уродлива, заключается в том, что вы открываете один и тот же обработчик файлов каждый раз, когда вводите блок $ start / $ stop.

    Это показывает способ обойти это:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $start='CINFILE=;
    my $stop='^#;
    my $filename;
    my $output;
    my $counter=1;
    my $found=0;
    
    while (<>) {
    
        # Find block of lines to extract                                                           
        if( /$start/../$stop/ ) {
    
            # Start of block                                                                       
            if( /$start/ ) {
                $filename=sprintf("boletim_%06d.log",$counter);
                open($output,'>>'.$filename) or die $!;
            }
            # End of block                                                                         
            elsif ( /$end/ ) {
                close($output);
                $counter++;
                $found = 0;
            }
            # Middle of block                                                                      
            else{
                if($found == 0) {
                    print $output (split(/ /))[1];
                    $found=1;
                }
                else {
                    print $output 

    Неплохо для того, чтобы прийти от «виртуального новичка». Одна вещь, которую вы могли бы сделать, - это поместить " $ found = 1 " внутри " if ($ found == 0) " блокировать, чтобы вы не делали это назначение каждый раз между $ start и $ stop.

    Еще одна вещь, которая, на мой взгляд, несколько уродлива, заключается в том, что вы открываете один и тот же обработчик файлов каждый раз, когда вводите блок $ start / $ stop.

    Это показывает способ обойти это:

    <*>; } } } # Find block of lines to extract }
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top