Соберите строки для каждой единицы в буфере; при каждой новой строке заголовка обрабатывайте предыдущий блок (проверьте последнюю строку в буфере, печатать или нет) и очистите буфер
use warnings;
use strict;
use feature 'say';
sub process_unit {
my ($rbuf) = @_;
if (not $rbuf->[-1] =~ tr/?@ABCDEFGHIJK//dr ) { #/ no extra chars
say for @$rbuf;
}
}
my $file = shift // die "Usage: $0 filename\n"; #/
open my $fh, '<', $file or die "Can't open $file: $!";
my @buf;
while (<$fh>) {
chomp;
if (/^\@/ and @buf) {
process_unit(\@buf);
@buf = ();
}
push @buf, $_;
}
process_unit(\@buf); # the last unit
Объяснение проверки последней строки в буфере с использованием tr
(задокументировано в perlop ):
tr/..//dr
удаляет все перечисленные символы из своей целевой строки, возвращая измененную строку, сохраняя оригинал без изменений (из-за «неразрушающего» модификатора /r
). Поэтому, если после удаления разрешенных символов остается что-либо, мы отбрасываем модуль (не печатайте его).
Примечание по выбору tr
и эффективности
Можно использовать регулярное выражение и его оператор сопоставления с классом отрицанных символов,
if (not /[^?\@ABCDEFGHIJK]/) { ... }
вместо оператора транслитерации tr
(который не регулярное выражение).
Однако, даже в самом лучшем случае для оператора матча я оцениваю подход tr
, чтобы он был 25%
быстрее. Во всех остальных случаях tr
опережает соответствие регулярному выражению, по крайней мере, в 2-4 раза.
Оператор соответствия «лучший случай» - это когда недопустимый символ находится на первой позиции в строке, чтобы он сразу совпадал и не сканировал остальную часть строки. Это довольно нереально, если не сказать больше.
Напротив, статистически во многих (большинстве?) Строках не будет ни одного из этих символов, и у оператора совпадения будет наихудший случай сканирования всей строки. (Но большая часть стоимости, вероятно, в любом случае, это запуск двигателя регулярного выражения.)