Использование Perl для печати нескольких строк
Этот код извлекает ключевое слово fun из имеющихся у меня текстовых файлов, а затем печатает 20 символов до и после ключевого слова. Тем не менее, я также хочу напечатать предыдущие 2 строки и следующие две строки, и я не уверен, как это сделать. Я не был уверен, проще ли изменить код с этим или просто прочитать весь файл за один раз.
{my $inputfile = "file";
$searchword = 'fun';
open (INPUT, '<', $inputfile) or die "fatal error reading the file \n";
while ($line1=<INPUT>)
{
#read in a line of the file
if ($line1 =~m/$searchword/i)
{print "searchword found\n";
$keepline = $line1;
$goodline =1;
$keepline =~/(.{1,20})(fun)(.{1,20})/gi;
if ($goodline==1)
{&write_excel};
$goodline =0;
}
2 ответа
Ваш код как есть кажется
- Не берите по 20 символов с каждой стороны
$searchword
; - Имейте непревзойденный '{' в начале;
- Не печатает содержимое файла, кроме & write_excel, которое мы не можем исследовать; а также
- Есть логическая проблема в том, что если
$searchword
найден,$goodline
безусловно устанавливается на "1", а затем проверяется, чтобы увидеть, является ли его "1" и, наконец, сбрасывается на "0"
Если оставить это в стороне, вопрос о том, нужно ли читать весь файл, зависит от ваших обстоятельств, а также от того, насколько велики файлы, которые вы собираетесь искать, у вашей машины достаточно памяти; машина является общим ресурсом и так далее. Я собираюсь предположить, вы можете прочитать в весь файл, как это более общая позиция в моем опыте (те, кто не согласен, пожалуйста, имейте в виду (а) Я квитирования, что его спорна, и (б) его очень сильно зависит от обстоятельства, которые знает только ОП)
Принимая во внимание, что есть несколько способов чтения целого файла, но консенсус, похоже, заключается в использовании модуля File::Slurp
, С учетом этих параметров ответ выглядит следующим образом;
#!/usr/bin/env perl
use v5.12;
use File::Slurp;
my $searchword = 'fun';
my $inputfile = "file.txt";
my $contents = read_file($inputfile);
my $line = '\N*\n';
if ( $contents =~ /(
$line?
$line?
\N* $searchword \N* \n?
$line?
$line?
)/x) {
say "Found:\n" . $1 ;
}
else {
say "Not found."
}
File::Slurp
выводит разумное сообщение об ошибке, если файл отсутствует (или что-то еще идет не так), поэтому я пропустил типичныйor die...
, Всякий раз, когда вы работаете с регулярными выражениями - особенно если вы пытаетесь сопоставить материал в нескольких строках, стоит использовать "расширенный режим" (помещая "x" после последнего "/"), чтобы разрешитьнезначительные пробелы в регулярном выражении. Это позволяет более четкое расположение.
Я также выделил определение линии для большей ясности, которая состоит из 0, 1 или более не-новых символов,\N*
, а затем новая строка,\n
, Однако, если ваша цель находится на первой, второй, второй-последней или последней строке, я предполагаю, что вы все еще хотите получить информацию, поэтому запрашиваемые предшествующая и последующая пары строк могут быть опционально сопоставлены. $line?
Обратите внимание, что регулярные выражения педантичны, и неизбежно возникают "мелкие детали", которые влияют на определение успешного сопоставления с нежелательным совпадением, т.е. Не ожидайте, что это сделаетименно то , что вы хотите при любых обстоятельствах. Ожидайте, что вам придется экспериментировать и немного подправлять.
Я не уверен, что понимаю ваш блок кода (для чего нужен "залог"? &write_excel
?), но я могу ответить на ваш вопрос сам.
Во-первых, приемлема ли эта команда grep? Это намного быстрее и чище:
grep -i -C2 --color "fun" "file"
-C NUM
флаг говорит grep
обеспечить NUM строк контекста, окружающих каждое совпадение с образцом. Очевидно, что --color
необязательно, но может помочь вам найти совпадения на очень длинных линиях.
В противном случае вот немного Perl:
#!/usr/bin/perl
my $searchword = "fun";
my $inputfile = "file";
my $blue = "\e[1;34m"; # change output color to blue
my $green = "\e[1;32m"; # change output color to green
my $nocolor = "\e[0;0m"; # reset output to no color
my $prev1 = my $prev2 = my $result = "";
open (INPUT, '<', $inputfile) or die "fatal error reading the file \n";
while(<INPUT>) {
if (/$searchword/i) {
$result .= $prev2 . $prev1 . $_; # pick up last two lines
$prev2 = $prev1 = ""; # prevent reusing last two lines
for (1..2) { # for two more non-matching lines
while (<INPUT>) { # parse them to ensure they don't match
$result .= $_; # pick up this line
last unless /$searchword/i; # reset counting if it matched
}
}
} else {
$prev2 = $prev1; # save last line as $prev2
$prev1 = $_; # save current line as $prev1
}
}
close $inputfile;
exit 1 unless $result; # return with failure if without matches
$result =~ # add colors (okay to remove this line)
s/([^\e]{0,20})($searchword)([^\e]{0,20})/$blue$1$green$2$blue$3$nocolor/g;
print "$result"; # print the result
print "\n" unless $result =~ /\n\Z/m; # add newline if there wasn't already one
Ошибка: это предполагает, что две строки до и две строки после на самом деле более 20 символов. Если вам нужно исправить это, он идет в else
строфа.