# Effect of redo on m//g

#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
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.

## Re: Effect of redo on m//g

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

## Re: Effect of redo on m//g

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.

Ben

## Re: Effect of redo on m//g

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

## Re: Effect of redo on m//g

Hmm... kind-of treating 'redo' as though it's going back in time? I
suspect if it is a feature it's accidental.

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;

In any case, the failing match is a red herring. 'redo' causes the same
'forgetting' of successful matches during the redone section:

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

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

Both matches there succeed, but the redo causes the 'last successful
match' to revert to the /f/ before the loop.

Ben

## Re: Effect of redo on m//g

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;
}

## Re: Effect of redo on m//g

<sigh> I'm just being stupid here :). The match variables are
*dynamically scoped* (each successful match effectively 'local's them):

"a" =~ /(.)/;
# \$1 eq "a"
{
"b" =~ /(.)/;
# \$1 eq "b"
}
# \$1 eq "a"

What's odd here is not that they are being reset, but that just going
round a loop again *doesn't* reset them. It seems anything out of the
ordinary, even just a 'continue { 1 }' block, is enough to bring the
normal scoping back.

Ben

## Re: Effect of redo on m//g

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

## Re: Effect of redo on m//g

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

## Re: Effect of redo on m//g

Yes, you can only use this when you are sure *one* of the set will
match.

Another example would be

perl -ne'/section: (.*)/ or print "\$1: \$_"'

Ben