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

This is a repost. The entire script is posted below, unlike before when everyone had the wrong idea (to my fault) at what the problem was.

Can someone help me figure out why it prints the last record X number of times rather than all the records of the hash as I want? For example, if I have two names in the hash "Me", "You" and I do this using [ab] (saying $ab is the name), it would print out "You" "You" when you run the script. It always prints the last record X number of times (it'll print 3 times if there are three keys, 10 times if there are 10). Can someone help me make it work so I can do all the substitutions for each key?

(Please don't comment on my variable names, I'll change those when I get this part working).

#!/usr/bin/perl use strict; use warnings; use POSIX; use CGI qw/:standard/; use CGI::Carp qw(fatalsToBrowser); require SDBM_File; my %data; my $data = "mylist.dbm"; my $specifics= param('specifics'); my $lookup = url_param('lookup'); tie %data, 'SDBM_File', $data, O_CREAT | O_RDWR, 0644; if ( !tied %data ) { print "error $!.\n"; } print header(); print start_html(); print <<"ALL"; <table width="470" border="0"> <form name="extract" method="post" action="extract.pl"> <tr><td colspan="2"><textarea name="specifics" cols="40" rows="5" id=" +specifics">$specifics</textarea></td></tr> <tr><td><input type="submit" name="submit1" value="submit"></td></tr> </form> </table> ALL if (param('submit1')) { foreach (sort keys %data) { my ($ab, $bb, $cb, $db, $eb, $fb) = split(/::/, $data{$_}); $specifics =~ s/\[a\]/$ab/; $specifics =~ s/\[b\]/$bb/; $specifics =~ s/\[more\]/$data{$_}/; $specifics =~ s/\[c\]/$cb/; $specifics =~ s/\[d\]/$db/; $specifics =~ s/\[e\]/$eb/; $specifics =~ s/\[f\]/$fb/; print "$specifics<br>"; } }

Replies are listed 'Best First'.
Re: Only printing last hash (repost)
by tilly (Archbishop) on Jan 04, 2004 at 03:53 UTC
    After the first pass through the loop, the variable $specifics has had all of the template variables edited out. On each subsequent pass, the edit doesn't change anything.

    Assign $specifics inside the loop and it will work much better. (I'd also suggest switching to any of the many templating modules on CPAN earlier rather than later. They'll take care of problems that you haven't, like what happens if $ab has [d] in it.)

Re: Only printing last hash (repost)
by neuroball (Pilgrim) on Jan 04, 2004 at 04:03 UTC

    Okay, now that we have the script we just need the input. Meaning the data returned by the database or at least a legend showing what kind of data is returned.

    But apart from this you might want to 'pepper' your perl script with a lot of print statements that will print out...

    • the hash after you received it from the database (Data::Dumper helps).
    • the key you get returned from foreach ($_)
    • the value you are accessing ($data{$_})
    • the variables you split the data into
    • $specifics, each time you ran a substitute on it

    The above exercise is called 'Debugging with print'. :)

    Now that you are printing all your data every step of the process, you can see where things go not as you expect them to.

    /oliver

Re: Only printing last hash (repost)
by pg (Canon) on Jan 04, 2004 at 05:44 UTC

    It is just false impression that this has anything to do with hash being mis-handled. In fact, after couple rounds through that foreach loop, the value of $specifics might become stable and maintain the same from then on, which then give you the impression that you are not getting all those different hash data, which you used to form target patterns of s///.

    I don't want to second guess your intention (requirement), but I guess $specifics probably should be reinitialized, or much better, to be declared inside the foreach loop. It is a good idea to always make sure your variables have the smallest possible scope. Lots of coding problems are caused by extended variable scopes.

    By the way, you defined two variables, one called %data, and one called $data. When it is 100% valid in Perl, it could cause confusions. I personally prefer to avoid it.

    Just a side note, the reason I said "after couple of rounds" and "might", is that:

    • Your s/// comes without g modifier, so there could be leftovers from previous rounds to be s///'d.
    • You have whole bunch of s///, so the pattern being replaced by one s///, could be reinserted by subsequent s///.
Re: Only printing last hash (repost)
by ysth (Canon) on Jan 04, 2004 at 06:58 UTC
    If you have input as: param('specifics') is "[a][b]" and you have $data{Foo} = "Bar::Baz::..." and $data{Boo} = "Far::Faz::...", what do you want your output to be?

    As is, it will be "FarFaz" twice, because Boo is processed first and $specifics doesn't have bracketed things left to substitute after that. If you want something different, it would be helpful to know what you would expect in this case.