Thanks for the explanation on persistence of the match variables. I was seeing it, but didn't believe it! I searched my Perl books, but didn't see that tidbit of information! Guess I need to upgrade my Perl library.
| [reply] |
There are references to many excellent sources in Getting Started with Perl but with so much information it can be difficult to find the tidbit you need sometimes.
Another excellent way to learn is by experiment and test. With practice your testing will become more thorough and your confidence in your own observations will grow accordingly.
In this case, I don't know that a better library would suffice. I think you have found a bug in perl. Capture buffers says:
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.)
According to this, I would expect the numbered match variables to go out of scope at the end of each iteration of the loop block and each new iteration to begin without them set, unless they were set in an outer context. But this is not what happens.
The behavior is quite different if a continue BLOCK is added to the loop. Consider the following:
use strict;
#use warnings;
my @array = ('<Band:3>40M <Call:5>KD4RR <QSL_Rcvd:1>Y <QSL_Sent:1>Y',
'<Band:3>40M <Call:5>K7RRR <QSL_Sent:1>Y',
'<Band:3>40M <Call:5>W7FAL <QSL_Rcvd:1>Y <QSL_Sent:1>Y');
foreach (@array) {
if(/<QSL_Rcvd:\d+>(Y)/i) {
print "Good Record: $_\n";
} else {
print "Bad Record: $_\n";
}
print "in loop: \$1 = $1\n";
} continue {
my $var = 1;
print "in continue: \$1 = $1\n";
}
print "after loop: \$1 = $1\n";
Which produces
Good Record: <Band:3>40M <Call:5>KD4RR <QSL_Rcvd:1>Y <QSL_Sent:1>Y
in loop: $1 = Y
in continue: $1 =
Bad Record: <Band:3>40M <Call:5>K7RRR <QSL_Sent:1>Y
in loop: $1 =
in continue: $1 =
Good Record: <Band:3>40M <Call:5>W7FAL <QSL_Rcvd:1>Y <QSL_Sent:1>Y
in loop: $1 = Y
in continue: $1 =
after loop: $1 =
With the continue block present, $1 is not set in the second iteration of the loop. One might argue that without the continue block the foreach statement doesn't leave its block until after the last iteration, but I am not aware of any documentation that says so and I find this behavior to be quite surprising. It seems obvious that the block is entered, executed and exited once with each iteration, whether there is a continue block present or not. Yet this is not the behavior, at least in perl 5.10.0
bug report | [reply] [d/l] [select] |
Thanks everyone for all the help. I followed the bug report ig submitted and see that the solution may be to update/clarify the documentation. My final solution was to put an empty continue at the end of the loop to make sure the match variables were reset and then added a test within the conditional loop to see if the match variable was initialized. Pretty much what everyone suggested. I put a comment at the empty continue explaining why it was there and included the bug report number. All in all, this just re-enforces the value of good test cases (at least to me)! One odd (but valid) record out of a thousand. Thanks again.
| [reply] |