Effect of redo on m//g

M

Mark

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.
 
B

Bo Lindbergh

Mark said:
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

C.DeRykus

Quoth Bo Lindbergh <[email protected]>:


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)
 
M

Mark

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

C.DeRykus

Quoth "C.DeRykus" <[email protected]>:
...

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.)
 
C

C.DeRykus

Quoth "C.DeRykus" <[email protected]>:

...
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"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top