eval within grep not working

  • Thread starter Krishna Chaitanya
  • Start date

Krishna Chaitanya


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’t 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.


Uri Guttman

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;


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Members online

No members online now.

Forum statistics

Latest member

Latest Threads