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

Hello Monks, I'll try to be brief. I'm a newbie trying to learn Perl with that cryptic tome, the Camel. I'm on "Fancy Patterns" and they are dealing with code within a regular expression. Can some enlightened Monk please, please explain this damn example??? Here it is:

$_ = "lothlorien"; m/ (?{ $i = 0 }) (. (?{ local $i = $i + 1; }) )* lori (?{ $result = $i }) /xi;

Now i = 4.

This example purportedly makes use of dynamic scoping. Unfortunately, the Camel has done a pretty crappy job explaining, or even using in examples, things like "local". The example right before this one was the exact same thing, but just used "$i++" instead of local, and didn't need the $result variable at the end. In that one, $i=10. A fellow monk explained to me that the .* greedily gobbles up the whole string, 10 characters, so $i gets incremented to 10 and the .* never matches again. (it only gives up some characters due to back-tracking). But in this one $i is 4!

I have no idea why, and my study has come to a grinding halt. Please help! Thanks :)

Replies are listed 'Best First'.
Re: reg-ex frustration
by japhy (Canon) on May 04, 2002 at 06:24 UTC
    Long story short, the use of local() makes $i become affected by backtracking. When the regex engine has to backtrack (since .* matched all of "lothlorien", and has to back up 6 characters), the modifications to $i are alos rolled back.

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a (from-home) job
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: reg-ex frustration
by tachyon (Chancellor) on May 04, 2002 at 06:02 UTC

    It is a pretty crappy example but what it does is include some code in the match regex which gets executed. Basically we try for a match with (pseudocode)m/.{0,length $_}lori/ and use $i to remember how many chars we needed to eat up to find "lori". There are far easier ways to do this like using pos() and a positive lookahead assertion if you want a regex solution or just plain old index():

    $_ = "lothlorien"; m/ (?{ $i = 0 }) (. (?{local $i = $i + 1; }) )* lori (?{ $result = $i }) /xi; print "\$result=$result \$i=$i\n"; # this provides the same answer but is IMHO much easier to understand m/(.*)(?=lori)/ig; print "pos=", pos; # this is probably the best solution print "index=", index($_, 'lori');

    You can't localise and use $i++ in the same statement.

    Update

    Fixed technical inexactitude thanks jryan

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: reg-ex frustration
by neilwatson (Priest) on May 04, 2002 at 14:16 UTC