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

John Macdonald <john-Z7w/En0MP3xWk0Htik3J/[email protected]> Mon, 24 Jan 2005 14:21:18 -0500
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
On Mon, Jan 24, 2005 at 01:11:33PM -0500, Daniel Martin wrote:
> Huh.  No one so far seems to have hit upon the solution I hit upon, which 
> was:  (I've deliberately left out most error checking since I want the 
> main script body uncluttered)
> 
> #!/usr/bin/perl
> use strict;
> 
> open(STDIN, '<', shift) if @ARGV;
> open(STDOUT, '>', shift) if @ARGV;
> 
> my $mline='';
> my $prefix='';
> 
> while(<>) {
>   /^(\w+)\.[A-Z]$/ or die "Bad line: $_";
>   if ($prefix ne $1) {
>     $prefix = $1;
>     print $mline;
>     $mline = "$prefix.M\n";
>   }
>   if ($mline lt $_) {
>     print $mline;
>     $mline = '';
>   }
>   print;
> }
> print $mline;
> __END__
> 
> 
> If I were into justifying my code with grand principles, I'd point out 
> that this is an example of the "null object" pattern 
> (http://c2.com/cgi/wiki?NullObject) - I end up doing {print $mline} often, 
> but when $mline is the empty string, this print statement has no effect. 
> Therefore I don't need several extra variables to track whether I've 
> already printed the proper thing or not, or whether I'm dealing with the 
> first line of the file, etc.  I dislike special cases, because I always 
> get into 1-off errors when dealing with them.  Using {print ''} as a no-op 
> allows me to do away with special cases.

Unfortunately, you've missed the other special case
where pre.M exists in the input - your code would
generate a second copy of that line.

I'd change:

  if ($mline lt $_) {
    print $mline;
    $mline = '';
  }

to:

  print $mline     if $mline lt $_;
  $mline = ''      if $mline le $_;

--