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

Hi there, The following code generates the all possible matches of the regex a(.*)a ==========================
$str = "abracadabra"; my @substrings; $str =~ m/ a (.*) a (.*)(?{push @substrings, $^N}) (?!) /x; use Data::Dumper 'Dumper'; print Dumper [ @substrings ];
============================= if i use for the matching line
my $regex="a (.*) a(.)*"; $str =~ m/ $regex(?{push @substrings, $^N}) (?!) /x;
gives the error
Eval-group not allowed at runtime, use re 'eval' in regex m/ a(.)*a(?{ +push @subs trings, $^N}) (?!) /
one second question how could i keep the positions of the matches and the lengths beside the matches themselves
$str =~ m/$regex(?{push @substrings, [$^N,$pos,length $^N]}) (?!) /x;
any suggestions? thanks in advance.

Replies are listed 'Best First'.
Re: all matches
by diotalevi (Canon) on Mar 25, 2004 at 05:59 UTC

    This is better written as a while loop.

    while ( /($regex)/gx ) { push @substrings, { match => $1, pos => ( pos() - length $1 ), length => length $1 }; }
      But this one doesn't handle overlapping cases and does match either greedyly or ungreedly but misses the ones not in between, doesn't it?

        Picky, pick! Just reset pos() and it does that. The difference between yours and my code is that the behaviour is well defined and I don't use anything marked "experimental." Whether the re engine finds an optimization which allows it to skip some execution is occasionally a problem with the sort of code that was originally proposed.

        An update. It pleased me to show just the added line by itself and then it occurred to me that this is better done in a continue block so that next() won't accidentally skip the positioning.

        while ( ... ) { ... } continue { # Reset the position of the regex match so that it will restart # just after the start of this match. This is done inside continue +{} # to safeguard itself against a next() that someone else might # add later. pos() = $-[0] + 1; }
        while ( /($regex)/gx ) { push @substrings, { match => $1, pos => ( pos() - length $1 ), length => length $1,}; # Restart the checking at one character after the match started. pos() = $-[0] + 1; }
Re: all matches
by BUU (Prior) on Mar 25, 2004 at 05:25 UTC
    Eval-group not allowed at runtime, use re 'eval' in regex m/ a(.)*a(?{ +push @substrings, $^N}) (?!) /
    The ?{} construct evaluates perl code inside a regular expression. By default it's off, so you want to do use re 'eval' to turn it on.
      To clarify, (?{}) constructs can be used without the use re 'eval' pragma, but only if the regex contains no elements interpolated from variables. Perhaps an example is called for:
      #fine /a (.*) a(.)*(?{push @substrings, $^N}) (?!)/ #not fine: we get part of the regex body from a variable /$regex(?{push @substrings, $^N}) (?!)/ ^^^^^^ this variable interpolation requires that you use re 'eval'
      Type perldoc re at your command prompt for more info.



      Code is (almost) always untested.
      http://www.justicepoetic.net/
        Thanks for the replies:)I checked the perldoc re and and it solved the eval problem but still although there is correct number of match in the array they are all undefined. I would appreciate any help? thanks
Re: all matches
by eyepopslikeamosquito (Archbishop) on Mar 26, 2004 at 08:00 UTC