Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

processing a file once within a nest for loop

by c (Hermit)
on Feb 15, 2002 at 14:18 UTC ( #145680=perlquestion: print w/replies, xml ) Need Help??

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

i ran into an interesting problem this morning that i was able to fix, but leaves me thinking that the script does a little more processing than it should/i want it to.
my code:

my @subs = qw( homer.bab); open(FH, "template") or die; my @tmpl = <FH>; close(FH); for my $i(@subs) { open(FH,">virt.$i") or die; for my $j(@templ) { $j =~ s/^(\w+)\@DOMAIN$/$1\@$i/; print FH $j; } close(FH) }

now, it makes sense that this works for the first value in @sub, but doesnt work for the remaining two, since each of the files opened will be written out with the first instance in the for $i loop, meaning that subsequent matches of DOMAIN won't be found. its easily remedied by matching against \w+ rather than an explicit DOMAIN, however, i end up processing more than i would like. when my @subs lists gets *very* long, that could be a bad thing. i continue to loop over it in my head, but i am not sure of the right way to do this.

thanks -c

Replies are listed 'Best First'.
Re: processing a file once within a nest for loop
by ferrency (Deacon) on Feb 15, 2002 at 14:55 UTC
    The reason why your code works as it does, is because when you use for or map, the loop variable is essentially a pointer to the value, not a copy of the value. So, if you change the value of the loop value, it changes the corresponding array element. This is the same behavior whether your loop variable is $_ or a lexical created with my.

    The easiest way to patch this to make it work is to copy the loop variable into another temporary variable before doing the substitution:

    # Warning, untested code below. for my $j(@templ) { my $k = $j; $k =~ s/^(\w+)\@DOMAIN$/$1\@$i/; print FH $k; } # Or: foreach (@templ) { my $j = $_; $j =~ s/^(\w+)\@DOMAIN$/$1\@$i/; print FH $j; }
    Some people don't like temporary variables, especially in cases like this, where it looks like you could remove the variable with no ill effect to the code (but you can't). But, since this is perl, there are other ways to do it. One would be to match $j and then do the replacement in the print statement instead of using s///:

    # Warning, untested code below. for (@templ) { /^(\w+)\@DOMAIN$/ and print FH "$1\@$i" or print FH; # implicitly prints $_ as usual } # Or if you prefer "if": for (@templ) { if (/^(\w+)\@DOMAIN$/) { print FH "$1\@$i"; } else { print FH; } }
    I hope these help.


Re: processing a file once within a nest for loop
by Speedy (Monk) on Feb 15, 2002 at 23:03 UTC
    You are right about having to protect the values in @tmpl. Once you change the word DOMAIN to the first @subs value, in your original code you have changed your template itself and can no longer substitute for DOMAIN -- in your case you now need to substitute for ""

    Try this sample code, where I substituted for the $j variable name something a bit more descriptive, and before each potential replacement saved each template string to a new "str_for_subbing" (and made up an "input" for the template file so I could see some real output).

    #!/usr/bin/perl use strict; my @subs = qw( homer.bab); my @tmpl = ("To: webmaster\@DOMAIN", "Dear Sir or Madam:", "You have +won \$1,000,000!"); my ($sub, $str, $str_for_subbing); for $sub(@subs) { open(FH,">virt.$sub") or die; # Assume @templ in your code should have been @tmpl # -- good reason to use strict! foreach $str (@tmpl) { $str_for_subbing = $str; $str_for_subbing =~ s/DOMAIN/$sub/g; print "$str_for_subbing\n"; print FH "$str_for_subbing\n"; } close(FH) }

    If you don't assign each $str to a $str_for_subbing, you do change the value of $str in the template on the first substitution for DOMAIN, which was not your intent. Substituting in a "copy" of each string saves you this grief.

    Live in the moment.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://145680]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (2)
As of 2023-06-02 19:10 GMT
Find Nodes?
    Voting Booth?

    No recent polls found