note
mr_mischief
<p>
You need to figure out if you're worried about overlapping matches, and specify your problem accordingly. There are solutions which will check excluded lines to see if there are additional lines to exclude after those. There are also solutions that will exclude a set of lines and move on as if the excluded lines after (but not before of course) the matched line can't possibly match. Here's an example of the difference.:
</p>
<c>
print me
exclude me
match me
match me
exclude me
print me
</c>
<p>vs:</p>
<c>
print me
exclude me
match me
would match me but the above line excluded me
print me anyway because the previous line wasn't matched after exclusion
print me
</c>
<p>
Here's a filter that will do either, based on a command-line argument. It also is configurable for how many additional lines to exclude (before, after, or both).:
</p>
<c>
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long ();
process( init() );
exit;
sub process {
my $opts = shift;
my @buffer = ();
my $wait = 0;
while ( <> ) {
if ( ( scalar @buffer ) > $opts->{ 'b' } ) {
print ( shift @buffer );
}
if ( $wait ) {
$wait--;
next unless $opts->{ 'nest' };
} else {
push @buffer, $_;
}
if ( /$opts->{ 'pattern' }/ ) {
@buffer = ();
$wait = $opts->{ 'a' };
}
}
print @buffer;
}
sub init {
my %options = (
'help' => 0,
'a' => 1,
'b' => 1,
'c' => 0,
'nest' => 0,
'pattern' => '',
);
Getopt::Long::Configure( 'gnu_getopt' );
Getopt::Long::GetOptions( \%options, 'help+', 'a=i', 'b=i', 'c=i', 'nest+', 'pattern=s' );
if ( $options{ 'c' } ) {
$options{ 'a' } = $options{ 'b' } = $options{ 'c' };
}
if ( $options{ 'help' } ) {
warn "Usage: $0 [[--help]|[[-a <n>] [-b <n>]|[-c <n>]] [--nest] --pattern <s>\n\n"
. "Print the input file excluding the matched line provided by the -p argument and as many lines before and after that line as specified.\n\n"
. "\t--help\t\t\tthis help message\n"
. "\t-a <number>\t\texclude <number> lines after the matched line\n"
. "\t-b <number>\t\texclude <number> lines before the matched line\n"
. "\t-c <number>\t\texclude <number> lines before and after the matched line, overriding -a and -b in the process\n"
. "\t--nest\t\t\tmatch lines already excluded by a preceding match, and exclude the following lines accordingly\n"
. "\t--pattern <string>\texclude the line matching this pattern (may be a regular expression) and other lines as specified by the other options\n\n";
exit 0;
}
return \%options;
}
</c>
<p>
I made it a filter as the file handling itself is kind of secondary to the problem at hand. It's possible to add input and output arguments either positionally or via flags. My preference if I were to flesh it out a bit more would be to default to STDIN and STDOUT but allow flags to override one, the other, or both.
</p>
1153137
1153137