Velocity Reviews > Perl > Effect of redo on m//g

# Effect of redo on m//g

Mark
Guest
Posts: n/a

 06-30-2009
Can someone please explain to me how the redo is affecting the match
results?

Case 1 - without redo:
use strict;
use warnings;

my \$bail = 0;

while () {
'ab' =~ /(.)/g;
print "\\$1=", defined(\$1) ? \$1 : 'undef', "\n";
last if \$bail++ > 5;
# redo;
}

Output:
\$1=a
\$1=b
\$1=b
\$1=a
\$1=b
\$1=b
\$1=a

Case 2 - with redo:
use strict;
use warnings;

my \$bail = 0;

while () {
'ab' =~ /(.)/g;
print "\\$1=", defined(\$1) ? \$1 : 'undef', "\n";
last if \$bail++ > 5;
redo;
}

Output:
\$1=a
\$1=b
\$1=undef
\$1=a
\$1=b
\$1=undef
\$1=a

It seems to me that redo should have no affect in the second case
below. It appears that when pos is past the end of the string, \$1 is
not set in Case 1 but it is reset to undef in Case 2.

Bo Lindbergh
Guest
Posts: n/a

 06-30-2009
In article <(E-Mail Removed)>,
Mark <(E-Mail Removed)> wrote:

> use strict;
> use warnings;
>
> my \$bail = 0;
>
> while () {
> 'ab' =~ /(.)/g;
> print "\\$1=", defined(\$1) ? \$1 : 'undef', "\n";
> last if \$bail++ > 5;
> # redo;
> }

An unsuccessful match doesn't modify \$1 and friends, so you should
in general only look at their values after a successful match.

/Bo Lindbergh

C.DeRykus
Guest
Posts: n/a

 06-30-2009
On Jun 30, 4:14*pm, Ben Morrow <(E-Mail Removed)> wrote:
> Quoth Bo Lindbergh <(E-Mail Removed)>:
>
>
>
> > In article <(E-Mail Removed)>,
> > *Mark <(E-Mail Removed)> wrote:

>
> > > use strict;
> > > use warnings;

>
> > > my \$bail = 0;

>
> > > while () {
> > > * * 'ab' =~ /(.)/g;
> > > * * print "\\$1=", defined(\$1) ? \$1 : 'undef', "\n";
> > > * * last if \$bail++ > 5;
> > > # * redo;
> > > }

>
> > An unsuccessful match doesn't modify \$1 and friends, so you should
> > in general only look at their values after a successful match.

>
> While this is correct, it doesn't answer the question 'why, then, does
> redo appear to be resetting \$1 to undef?'. I think it's a bug in perl,
> and IIRC it's a known (and probably won't-fix) bug. 'redo' causes perl
> to forget which pattern was the last one you matched, and since the \$N
> are actually stored in the pattern this causes \$1 to revert to the last
> successful pattern match *before* the loop that was redone. Try adding
>
> * * "f" =~ /(f)/;
>
> before the loop to see what I mean.
>

Interesting. Maybe, it's considered a feature

(And just to be pedantic, the OP shouldn't try to
get the "full monty" anyway if the match fails)

--
Charles DeRykus

Mark
Guest
Posts: n/a

 07-01-2009
And.. the execution doesn't even need to reach the redo for it to have
an effect.

"f" =~ /(f)/;
my \$last;

while (1) {
"a" =~ /(a)/ unless \$last;
say \$1;
last if \$last++;
next; # <<----------
redo;
}

C.DeRykus
Guest
Posts: n/a

 07-01-2009
On Jun 30, 5:54*pm, Ben Morrow <(E-Mail Removed)> wrote:
> Quoth "C.DeRykus" <(E-Mail Removed)>:
> ...

> > (And just to be pedantic, the OP shouldn't try to
> > * get the "full monty" anyway if the match fails)

>
> Both you and Bo have said that, and it *simply* *isn't* *true*. The
> match variables being preserved across failing matches is an entirely
> supported feature, useful in situations like
>
> * * s/(foo)/bar/;
> * * s/(baz)/quux/;
>
> * * my \$replaced = \$1;
>

Sigh... the OP was actually pointing out that redo
didn't preserve the failed matches. And I see your
subsequent post exposes the real scoping issue
mentioned in perlre:

The numbered match variables (\$1, \$2, \$3, etc.)
and the related punctuation set (\$+, \$& ,\$`, \$',
and \$^N ) are all dynamically scoped until the end
of the enclosing block or until the next successful
match, whichever comes first. (See ""Compound
Statements"" in perlsyn.)

--
Charles DeRykus

C.DeRykus
Guest
Posts: n/a

 07-01-2009
On Jun 30, 5:54*pm, Ben Morrow <(E-Mail Removed)> wrote:
> Quoth "C.DeRykus" <(E-Mail Removed)>:
>
> ...
> Both you and Bo have said that, and it *simply* *isn't* *true*. The
> match variables being preserved across failing matches is an entirely
> supported feature, useful in situations like
>
> * * s/(foo)/bar/;
> * * s/(baz)/quux/;
>
> * * my \$replaced = \$1;
>

I haven't used this feature but, it occurs
to me, with the scoping issues you found,
the replacement might be a bit dodgy:

"f" =~ /(f)/;
...
\$_ = "one two three";
s/(foo)/bar/;
s/(baz)/quux/;
my \$replaced = \$1; # = "f"

> ...

--
Charles DeRykus