2009-07-31 7 views
11

У меня есть файл журнала ASCII с некоторым контентом, который я хотел бы извлечь. Я никогда не занимался изучением Perl, но считаю, что это хороший инструмент для этой задачи.Как извлечь строки между двумя разделителями строк в 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 или других элементов документации, которые несколько связаны с тем, что я ищу.

+0

использовать глобальный матч/г, а не позволяя ему остановиться на линии терминатора. – Lazarus

+0

Вы имели в виду/s? AFAIK/g является ** множественным ** совпадением. –

+1

Это дублированный вопрос. Смотрите ... http://stackoverflow.com/questions/296366/how-can-i-extract-lines-of-text-from-a-file/296672#296672 – draegtun

ответ

22

Вы хотите оператора флип-флоп (более известный как оператор диапазона) ..

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

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

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

+0

Работает для меня !! Поскольку я хочу исключить строки с разделителями, я могу передать вывод через grep -v, например. BTW, в первой строке после START, как я мог удалить первый символ в строке? – jbatista

+3

+1 для триггера –

+1

Версия с одним слоем: perl -ne 'print if /START/../END/' –

1

How can I grab multiple lines after a matching line in Perl?

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

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

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

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

+0

Я понимаю, и я бы написал код, если бы уже начал изучать Perl. Мне удалось пройти с awk и sed до сих пор. Но в любом случае спасибо за ваш совет. – jbatista

1

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

  1. Я пытаюсь извлечь строки, ограниченные двумя строками (один, с линией, заканчивающейся «CINFILE =»; другой, с линией, содержащей один «#») в отдельных строках, за исключением разделительные линии , Это я могу сделать с решением Telemachus.
  2. В первой строке есть пробел, который я хочу удалить. Я также включаю его.
  3. Я также пытаюсь извлечь каждый набор строк в отдельные файлы.

Это работает для меня, хотя код можно классифицировать как уродливый; это потому, что я в настоящее время практически новичок в 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 $_; } 
    $found=1; 
    } else { if($found == 1) { close($output); $counter++; $found=0; } } 
} 

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

5

От ответа perlfaq6 «s к How can I pull out lines between two patterns that are themselves on different lines?


Вы можете использовать в 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 $. 
} 
1

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

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

Это показывает путь вокруг этого:

#!/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 $_; 
      } 
     } 

    } 
    # Find block of lines to extract               

} 
+0

Спасибо. Теперь я чувствую, что я должен потратить некоторое время, чтобы правильно изучить Perl. Мой фон находится на C, некоторых C++ и некоторых Fortran, поэтому он кажется знакомым. – jbatista

+0

BTW, я признаю, что я был слабым при открытии многих файлов, моя главная забота в то время заключалась в том, чтобы получить что-то, что действительно работало, даже если не слишком хорошо. – jbatista

 Смежные вопросы

  • Нет связанных вопросов^_^