eval within grep not working

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

Am trying the exercise in Chapter 17 of Learning Perl....for those who
don't have that book, here is the question:

"Make a program that reads a list of strings from a file, one string
per line, and then lets the user interactively enter patterns that may
match some of the strings. For each pattern, the program should tell
how many strings from the file matched, then which ones those were.
Don=92t reread the file for each new pattern; keep the strings in
memory. The filename may be hardcoded in the file. If a pattern is
invalid (for example, if it has unmatched parentheses), the program
should simply report that error and let the user continue trying
patterns. When the user enters a blank line instead of a pattern, the
program should quit."

I came up with this code:



use strict;
use warnings;
use diagnostics;

open FH, "abc" or die "Cannot open file: $!\n";
my @file_contents = <FH>;

while(1) {
  chomp(my $pattern = <STDIN>);
  last if $pattern =~ /^\s*$/;
  my @matched = grep {
                        my $line = $_;
                        eval { $line =~ /$pattern/ };
                        if ($@) {
                          print "Error in pattern : $@\n";
                     } @file_contents;
  print "Number of matched lines = ", scalar @matched, "\n";
  print "Matched lines are:\n @matched\n";

It doesn't work...for simple patterns like "This", "cat", etc. Oh, and
file "abc" contains:

This is a cat
This is a dog
This is a ball

But it works if I put the eval outside the grep (as mentioned in the
solution to the exercise in that book). I thought the code block for
grep in my code above always returns either true/false......but it's
not working. Can you pls. help me by pointing out the mistake?

Am using Perl 5.8.8 on Linux, if it matters.


Re: eval within grep not working

  KC>   my @matched = grep {
  KC>                         my $line = $_;
  KC>                         eval { $line =~ /$pattern/ };
  KC>                         if ($@) {
  KC>                           print "Error in pattern : $@\n";
  KC>                           undef;
  KC>                         }
  KC>                      } @file_contents;

your problem is simple. you don't pass the result of the match to
grep. it is using the last expression evaluated as its boolean (likely
the if()). so you can do one of two things: save the results of the eval
and pass that to grep, or eval a qr// to check the regex validity and
then do the match at the end. here are untested examples:

  my @matched = grep {
                        my $line = $_;

# that isn't needed even though i always used named vars. in this short
# context, $_ is fine
                       my $match = eval { $line =~ /$pattern/ };
                        if ($@) {
                          print "Error in pattern : $@\n";
# exit the grep and get another user line. this is what the exercise
# asks for
                          next ;

                     } @file_contents;

# this version also moves the pattern verifyer outside the grep where it
# belongs. makes the grep short and easy to read as well.

    my $pat = eval { qr/$pattern/ };
    unless( $pat ) {
        print "Error in pattern : $@\n" ;
        next ;

    my @matched = grep /$pat/, @file_contents;


Uri Guttman  ------  uri@stemsystems.com  --------  http://www.sysarch.com --
-----  Perl Code Review , Architecture, Development, Training, Support ------
---------  Gourmet Hot Cocoa Mix  ----  http://bestfriendscocoa.com ---------

Site Timeline