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

Hello,

I use ActiveState Perl 5.12.2. I'm surprized:

'a' =~ /^(?(?=b)b)a$/ # Not match 'a' =~ /^(?(?=b))a$/ # Match

Why yes-subpattern attempts to match? The condition (?=b) must return false.

Regards,
Serge

Replies are listed 'Best First'.
Re: A bug in regex with conditional subpattern?
by moritz (Cardinal) on Mar 17, 2011 at 11:18 UTC
    After some discussion on #p5p, the conclusion seems:
    • The feature was a mess. It seems to work as intended on perl 5.13.8 and newer. In older version, the optimizer incorrectly rejected some matches
    • the intended behavior is that a missing no-pattern is the same as an empty no-pattern, ie the whole match succeeds if the condition fails and the no-pattern is missing. Thus both regexes should succeed.
Re: A bug in regex with conditional subpattern?
by BrowserUk (Patriarch) on Mar 17, 2011 at 10:21 UTC
    The condition (?=b) must return false.

    It does. The condition returns false, therefore it make no attempt to match the (null) yes pattern (which would have matched anyway), and simply moves on to the next element 'a$', which matches.

    In other words, if the condition of the conditional expression, in this case the lookahead assertion, is false, then no attempt is made to use either the yes pattern, or the no pattern (here missing). In effect, the entire construct becomes a noop.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      and simply moves on to the next element.

      And that's the bug, IMHO. If the yes-pattern is present, and the condition fails, the whole match normally fails. Why should it move on if the match fails? Compare:

      'a' =~ /^xa/ # match of x fails, doesn't move on to match a

      When the no-pattern is not present, and the condition fails, it normally doesn't match:

      $ perl -wE 'say "a" =~ /^(?(?=b)xxx)a/' $ # no match

      So it doesn't show the "move on"-behavior when the yes-pattern is something else than the empty pattern.

      So it's a special case. And it's not documented. So it's a bug.

        Why should it move on if the match fails?

        Is "(?(condition)yes-pattern)" an abbreviation for "(?(condition)yes-pattern|)" (i.e. with an explicitly empty no-pattern)? This seems most reasonable to me, but I find nothing in the documentation to suggest whether this or any other possibile behaviour should be expected.

        The most fundamental "bug" seems to be lack of documentation of intended behaviour.

      "In effect, the entire construct becomes a noop. "

      In which case the first line of Serge314's example should match, shouldn't it?