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

I have recently discovered the horrible truth
about combining loops and pattern matching. As you may have
guessed, the following will only work on the
initial values of $record and @BAN.
My understanding (basic, as it may be) is that the matching tables
are created at compile time, and, therefore, the
subsequent iterations of the loop will all look exactly
the same as the first interation.

Given that @BLIST is an array of file names,
and that @LOOP contains some HTML code,
Please consider the following:

foreach $record (@BLIST) { open(BAN, $record) || &Error($!); @BAN = <BAN>; close BAN; foreach $line (@LOOP) { $line =~ s/FNAME/$record/; $line =~ s/BANNER/@BAN/; print $line; } }

I have been researching this issue for a while and
cannot figure out how to make this work.
Any suggestions?

Thanks.

Replies are listed 'Best First'.
Re: Loops and Pattern Matching
by runrig (Abbot) on Sep 26, 2001 at 23:34 UTC
    Your changing the data in @LOOP during the first iteration of the outermost loop. After the first iteration, there's nothing left to substitute. You need to change the inner loop to something like this so that you're changing copies of the data in @LOOP, rather than @LOOP itself:
    foreach (@LOOP) { my $line = $_; $line =~ s/FNAME/$record/; $line =~ s/BANNER/@BAN/; print $line }
    I am also tempted to say use strict and warnings, but I'll refrain for now :)
Re: Loops and Pattern Matching
by tommyw (Hermit) on Sep 26, 2001 at 23:37 UTC

    From the perlsyn documentation:
    <cite>If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the "foreach" loop index variable is an implicit alias for each item in the list that you're looping over. </cite>

    So $line isn't a copy of the line from @LOOP: it actually is that line.

    foreach (@LOOP) { my $line=$_; # Don't want to modify the orginal! $line =~ s/FNAME/$record/; $line =~ s/BANNER/@BAN/; print $line; }
    ought to do what you want.
Re: Loops and Pattern Matching
by dragonchild (Archbishop) on Sep 26, 2001 at 23:48 UTC
    Firstly, use strict. Use warnings. It's possible that your error could be related to that. (The other posters do have very good points, too.)

    Secondly, your logic seems to be a little sketchy. You're doing the operations on @LOOP several times, once for each file. But, you never reset @LOOP. It's not a pattern-matching problem, but a logic issue. Instead, consider:

    foreach my $record (@BLIST) { open(BAN, $record) or &Error($!); my @BAN = <BAN>; close BAN; my @tempLOOP = @LOOP; foreach my $line (@tempLOOP) { $line =~ s/FNAME/$record/; $line =~ s/BANNER/@BAN/; print $line; } }

    In addition, I would highly reccomend using the HTML templating modules that have already been written, vs. rolling your own. (That is what you're doing, right?)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.