[SPOILER] Perl 'Easy' Quiz of the Week #2005-1

Bill Smith <[email protected]> Mon, 24 Jan 2005 10:46:25 -0500
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <000a01c5022b$ddd1f160$ab00a8c0@hfwk801>
The attached file includes my implementation and its manpage documentation (in POD).

My solution includes the option of using defaults for output and input.

The actual processing is straightforward, but probably reflects my FORTRAN background.  The problem of dividing a file into groups of similar records is very common.  I look forward to learning a more perl oriented approach to the more general problem.
ricfiltr.pl (text/plain, 4 KB)
#!C:\perl\bin\perl

=pod

=head1 NAME

ricfiltr  -- Program to insert '.M' records as necessary

=head1 SYNOPSIS

S<B<perl ricfiltr.pl> [I<infile> [I<outfile>]]>

=head1 DESCRIPTION

This program examines each group of input lines with the same prefix.
If none of the lines has the suffix 'M', a line I<prefix>.M is inserted.
L<"FILES"> for details of "prefix" and "suffix".

=head1 OPTIONS

=over 4

=item infile (default: STDIN)

=item outfile (default: STDOUT)

This option is not valid unless infile is also specified.

=back

=head1 DIAGNOSTICS

Fatal Errors

=over 4

=item "usage: perl ricfiltr.pl [infile [outfile]]"

To many arguments on command line. L<"SYNOPSIS">

=item "unable to open output file I<outfile>"

You probably do not have write access to the directory.

=item "unable to open input file I<infile>"

File does not exist or current directory is set incorrectly.

=back

Warnings

=over 4

=item "Invalid input line -- line ignored"
 (invalid line)

Invalid line found in input.
It is B<NOT> coppied to output.

=back

=head1 EXAMPLES

=over 4

=item Output to STDOUT

      perl ricfiltr.pl test1

=item Output to file

       perl ricfiltr.pl test2 result2

=item Filter

       echo C.X| perl ricfiltr.pl | more

=back

=head1 ENVIROMENT

There are no known references to enviroment variables.

=head1 FILES

Input and output files have identical format.
They consist of zero or more lines sorted into alphabetical order.

Each line consists of a prefix, a period, and a suffix (without any whitespace).

The prefix consists of one or more "word characters".

The suffix consists of a single upper case letter.


=head1 TEST

The following examples have been tested only under Windows ME.


=head2 Add .M line after last line

 echo C.X > test1
 perl ricfiltr.pl test1

     C.M
     C.X

=head2 Add .M lline before first line


 echo C.G > test2
 perl ricfiltr.pl test2

     C.G
     C.M

=head2 Null input file

 perl ricfiltr.pl nul
 (No output)

=head2 File consists only of a .M record.

 echo C.M > test4
 perl ricfiltr.pl test4

     C.M

=head2 Test case provided by qotw.

 type test5        (cat test5 in unix)
     ALDA.D
     ALDA.Q
     ALDA.W
     AMTA.B
     AMTA.E
     AMTA.M
     AMTA.X
     BMX.F
     C.X
     DMZ.A

 perl ricfiltr.pl test5
     ALDA.D
     ALDA.M
     ALDA.Q
     ALDA.W
     AMTA.B
     AMTA.E
     AMTA.M
     AMTA.X
     BMX.F
     BMX.M
     C.M
     C.X
     DMZ.A
     DMZ.M

=head1 NOTES

This program implements the perl-qotw "Easy Quiz of the Week 2005-1"

This documentation is intended to conform to the manpage spec in
perldoc pod2man.

=head1 AUTHOR

Willilam K. Smith

=cut

use strict;
use warnings;

if (@ARGV > 2) {  # More than 2 arguments?
	die "
	
	usage:
	perl ricfiltr.pl [infile [outfile]]\n\n\n";
}

if ($ARGV[0]){
	open (INFILE, $ARGV[0]) or die
		"unable to open input file $ARGV[0]\n";

	if ($ARGV[1]){
		open (OUTFILE, '>', $ARGV[1]) or die 
			"unable to open output file $ARGV[1]\n";

	}else{ # No output specified.  Use default.
		*OUTFILE = *STDOUT;
	}

}else{ # No files specified.  Use defaults.
	*INFILE = *STDIN;
	*OUTFILE = *STDOUT;
}

my $oldprefix='';
my $mflag=0; # .M line has not yet been printed.
my $prefix;
while (<INFILE>){
	
	($prefix, my $suffix) = (/^(\w+)\.([A-Z])\n?$/);

	unless (defined $prefix and defined $suffix){
		warn "Invalid input line -- line ignored\n$_\n";
		next;
	}

	if ($prefix gt $oldprefix){ # Start of new group?

# 		Put .M line at end of  previous group (if needed)
		print OUTFILE "$oldprefix.M\n" unless ($mflag or $oldprefix eq '');
#		Start new group
		$mflag = 0;
		$oldprefix = $prefix;
	}
	
	unless ($mflag){  # .M line for group not already output?
		if ($suffix ge 'M'){
			$mflag = 1;
			if ($suffix gt 'M'){
#				Put .M line before current line
				print OUTFILE "$prefix.M\n"; 
			}
		}
	}

	print OUTFILE; # print input record

} # End of main loop

# .M record for end of last group (if needed)
print OUTFILE "$prefix.M\n" unless $mflag or !defined $prefix;



sub gethandles{

	return (*STDIN, *STDOUT);	
}