Как извлечь строки между двумя разделителями строк в Perl?
Вопрос
У меня есть файл журнала 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;
}
попробуйте написать код в следующий раз
После ответа Телемаха все стало течь. Это работает как решение, которое я смотрю в конце концов.
<Ол>Это работает для меня, хотя код можно классифицировать как некрасивый; это потому что я в настоящее время практически новичок в 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
}