isotope has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to pass a precompiled regular expression to grep(), but instead of properly matching, grep returns the entire array. Putting the precompiled regex in // produces the desired behavior. Seen in 5.6.1 and 5.8.0.

Here's a sample testcase:
#!/usr/bin/perl -w use strict; use Test::More tests => 3; use Test::Differences; my @input = qw(nope skip uh-uh no yes stop yup not-me groovy wrong ok +ay); my @output = qw(yes yup groovy okay); my $re = qr/y/; eq_or_diff( [ grep( /y/, @input ) ], \@output, "Embedded RE" ); eq_or_diff( [ grep( $re, @input ) ], \@output, "Compiled, passed RE" + ); eq_or_diff( [ grep( /$re/, @input ) ], \@output, "Compiled, but slashe +d RE" );
Test 2 fails; grep has returned the whole input array:
grep_re....1..3
ok 1 - Embedded RE
not ok 2 - Compiled, passed RE
#     Failed test (grep_re.t at line 13)
# +----+--------+----+----------+
# | Elt|Got     | Elt|Expected  |
# +----+--------+----+----------+
# *   0|nope    *    |          |
# *   1|skip    *    |          |
# *   2|uh-uh   *    |          |
# *   3|no      *    |          |
# |   4|yes     |   0|yes       |
# *   5|stop    *    |          |
# |   6|yup     |   1|yup       |
# *   7|not-me  *    |          |
# |   8|groovy  |   2|groovy    |
# *   9|wrong   *    |          |
# |  10|okay    |   3|okay      |
# +----+--------+----+----------+
ok 3 - Compiled, but slashed RE
# Looks like you failed 1 tests of 3.
dubious
        Test returned status 1 (wstat 256, 0x100)
DIED. FAILED test 2
        Failed 1/3 tests, 66.67% okay
Failed Test Stat Wstat Total Fail  Failed  List of Failed
-------------------------------------------------------------------------------
grep_re.t      1   256     3    1  33.33%  2
Failed 1/1 test scripts, 0.00% okay. 1/3 subtests failed, 66.67% okay.
Has anyone else experienced this?

Update: Changed title to be more clear.


--isotope

Replies are listed 'Best First'.
Re: Grep bug -- doesn't handle passed, precompiled regular expressions properly
by Roy Johnson (Monsignor) on Nov 30, 2005 at 21:02 UTC
    When you don't put the slashes on, you're just testing the variable. $re (having a regex value) is true. /$re/ is a pattern match which can be true or false.

    Caution: Contents may have been coded under pressure.
Re: Grep bug -- doesn't handle passed, precompiled regular expressions properly
by Fletch (Bishop) on Nov 30, 2005 at 21:02 UTC

    Erm, I think the problem is with what you expect grep EXPR, LIST to do with a compiled regex in this case. If EXPR evaluates to a true value, the element is returned. A compiled regex instance is a true value (it's not undef or one of the many faces of 0), so every element will be returned; it's not compared against anything as you haven't told it to do anything with it.

Re: Grep matches all elements if compiled regex is passed as EXPR
by ikegami (Patriarch) on Nov 30, 2005 at 21:07 UTC

    The following works:

    grep $_=~$re, ...

    Your problem is unrelated to grep. In

    if (/re/ ) { ...a... } if ($re ) { ...b... } if (/$re/ ) { ...c... } if ($_=~$re ) { ...d... } if ($_=~/$re/) { ...e... }

    ...b... will always be executed if $re contains a compiled regexp. Others have already explained why.

Re: Grep matches all elements if compiled regex is passed as EXPR
by GrandFather (Saint) on Nov 30, 2005 at 21:11 UTC

    grep evaluates an expression, unlike split which matches a pattern. Consider:

    use strict; use warnings; my $re = qr/y/; $_ = 'yep'; print /y/; print "\n".$re; print "\n"./$re/;

    which prints:

    1 (?-xism:y) 1

    DWIM is Perl's answer to Gödel
Re: Grep matches all elements if compiled regex is passed as EXPR
by tphyahoo (Vicar) on Dec 02, 2005 at 13:36 UTC
    I would explain this by saying that there is no operator acting against the default variable $_ in test 2. Tests 1 and 3 could be rewritten $_ =~ m/y/ and $_ =~ m/$re/ but test 2 can't be rewritten as anything. In short, there's no operator, just a value, which will always be true.