Как извлечь строки между двумя разделителями строк в 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
строка или другое элементы документации, которые несколько связаны с тем, что я ищу.
6 ответов
вы хотите оператор триггера (более известный как оператор диапазона) ..
#!/usr/bin/env perl
use strict;
use warnings;
while (<>) {
if (/START/../END/) {
next if /START/ || /END/;
print;
}
}
замените вызов print
С тем, что вы действительно хотите сделать (например, вставьте линию в массив, отредактируйте ее, отформатируйте ее, что угодно). Я next
-ING мимо строк, которые на самом деле имеют START
или END
, но вы можете не хотеть такого поведения. См.в этой статье для обсуждения этого оператора и других полезных специальных переменных Perl.
С perlfaq6ответом как я могу вытащить линии между двумя шаблонами, которые сами по себе находятся на разных линиях?
вы можете использовать несколько экзотические Perl .. оператор (описана в perlop):
perl -ne 'print if /START/ .. /END/' file1 file2 ...
Если бы вы хотели текст, а не строки, вы бы использовали
perl -0777 -ne 'print "\n" while /START(.*?)END/gs' file1 file2 ...
но если вы хотите вложенные вхождения от начала до конца, вы столкнетесь с проблемой, описанной в вопросе в этом разделе о сопоставлении сбалансированный текст.
вот еще один пример использования ..:
while (<>) {
$in_header = 1 .. /^$/;
$in_body = /^$/ .. eof;
# now choose between them
} continue {
$. = 0 if eof; # fix $.
}
Как я могу захватить несколько строк после строки в Perl?
Как это? В этом случае конечная строка равна$^, вы можете изменить ее на свою конечную строку.
Я также новичок, но решения там предоставляют довольно много методов... дайте мне знать более конкретно, что вы хотите, что отличается от приведенной выше ссылки.
while (<>) {
chomp; # strip record separator
if(/END/) { $f=0;}
if (/START/) {
s/.*START//g;
$f=1;
}
print $_ ."\n" if $f;
}
попробуйте написать код в следующий раз вокруг
после ответа Телемаха началось излияние. В конце концов, это работает как решение, на которое я смотрю.
- Я пытаюсь извлечь строки, разделенные двумя строками (одна строка заканчивается на "CINFILE="; другая строка содержит одну "#") в отдельных строках, исключая строки разделителя. Это я могу сделать с помощью решения Телемаха.
- в первой строке есть пробел, который я хочу удалить. Я также включаю его.
- Я также пытаюсь извлечь каждая строка-набор в отдельные файлы.
это работает для меня, хотя код можно классифицировать как уродливый; это потому, что я в настоящее время практически новичок в 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; } }
}
Я надеюсь, что это принесет пользу и другим. Овации.
Не так уж плохо, что пришли от "виртуальной 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
}