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

hi all,

I'm looking for an explanation. I've crafted some code, it does what I want (well, that's what i think)... but now I want to know why ;-)

I have a if statement with a call to a method in a regular expression. I use the ??{ } construction in the regular expression in order to execute the method. (maybe there's a better way?)

package MyClass; my $cnt; sub new { return bless { cnt => 0 }; } sub gimme_sweet_love { my $self = @_; $self->{cnt} += 1; return "hell yeah" } sub cnt { my $self = @_; return $self->{cnt} } package main; use strict; use warnings; local $\ = $/; my $match = "hell yeah"; my $obj = MyClass->new(); my $re = qr/(??{ ${obj}->gimme_sweet_love })/; print "\$match value:", $match; print "HURAY (m)" if $match =~ m/$re/; print "count = ".$obj->cnt; $match = "hell no"; print "\$match value:", $match; print "HURAY (m)" if $match =~ m/$re/; print "count = ".$obj->cnt;
The output goes as follows:
$match value:hell yeah HURAY (m) count = 1 $match value:hell no count = 9

So, when there's no match, the above method $obj->gimme_sweet_love is executed "the number of chars" times, could someone tell me why?

when there's a match, the method is executed only once.

Thanks a lot

to ask a question is a moment of shame
to remain ignorant is a lifelong shame

Replies are listed 'Best First'.
Re: ??{ } oddity
by Joost (Canon) on Apr 28, 2005 at 12:35 UTC
    Code in ??{ .. } is executed to produce a subexpression that then is tested to see if there is a match.

    In your case this means that if the subexpression matches, the m// match is done and the code is not called again.

    If it doesn't match, the expression is moved forward by one character and tries to match again (which calls the code again, because if you use a code block, you'll likely want to return a different match expression).

    It's very likely you can use a more efficient technique here, but that depends on what you actually want to do.

      ah ok, thanks!

      a friend of mine asked me this question (well, actually he asked how he could execute a piece of code, well actually call a method, in a m//. i made the method return a static value, but it will mostly likely do something else..)

      he gave me a theoretical example of what he was trying... so i don't really know what his intentions were. I just found the ??{ } expression in perldoc perlre.

      but thanks for the answer, i understand the behaviour now

      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame

        A regex is a double-quote-ish expression, so variables are interpolated, including dereferencing references. Any block of code can be stuck in place of a reference (it should return a reference, in order to dereference properly). So you can execute any code you want within a regex or a string. The result of the block will be dereferenced and interpolated into the string (here I return a ref to an empty string, so the pattern isn't changed):

        It will be executed each time the regex is looked at (compiled), even if the match doesn't get that far. For example:

        for (qw{dog pig cat horse}) { /.o${print "$_ gets printed\n";\''}/ and print "$_ matched\n"; } __END__ dog gets printed dog matched pig gets printed cat gets printed horse gets printed horse matched
        Contrast that with (?{}), which executes arbitrary code if the expression matched up to that point (and does not insert anything into your pattern):
        for (qw{dog pig cat horse}) { /.o(?{print "$_ gets printed\n"})/ and print "$_ matched\n"; } __END__ dog gets printed dog matched horse gets printed horse matched
        And finally (??{}), which acts the same, but does insert into your pattern:
        for (qw{dog pig cat horse}) { /.o(??{print "$_ gets printed\n"; 'g'})/ and print "$_ matched\n"; } __END__ dog gets printed dog matched horse gets printed
        The latter two are "experimental" features, but ref interpolation is not.

        Caution: Contents may have been coded under pressure.
Re: ??{ } oddity
by Roy Johnson (Monsignor) on Apr 28, 2005 at 17:09 UTC
    I think you want
    my $re = qr/(${ \$obj->gimme_sweet_love })/;

    Caution: Contents may have been coded under pressure.
      perfect!
      the following code now works as i wanted it to.. thanks a lot!

      my $re = qr/(${ \$obj->gimme_sweet_love })/; for my $match ( qw(yes yeah ja jup ok) ) { print "\$match value:", $match; print "HURAY (m)" if $match =~ m/$re/; print "count = ".$obj->cnt; }
      this gives:
      $match value:yes count = 1 $match value:yeah HURAY (m) count = 1 $match value:ja count = 1 $match value:jup count = 1 $match value:ok count = 1

      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame