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

I'm a newbie to Perl so I'm sure this will some obvious thing I'm overlooking.
# I open the file of query strings open (DATABASE, "$Raw_data"); flock(DATABASE, 2); @database=<DATABASE>; flock(DATABASE, 8); close DATABASE; # read each line in foreach $database (@database) { chomp $database; @pairs = split(/&/, $database); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1 +))/eg; $value =~ s/~!/ ~!/g; if ($in{$name}) { $value = $in{$name}.", ".$value; } $in{$name} = $value; } # assign values to variables $NAME=$in{'NAME'}; $AMOUNT=$in{'AMT'}; # print variables to see values print "$NAME - $AMOUNT<br>";

For the test file there were 32 lines. The problem is $NAME and $AMOUNT get larger each time the file is read.

I've tried using a counter and setting up hashes like $NAME[$counter] and $AMT[$counter] but the same thing happens.

I've also tried $NAME = ""; $AMT = ""; at the end to erase any values.

I just need to know how to set the values for $NAME and $AMT to null values each time a line is processed.

Thanks,
Jeri


Edit ar0n 2001-07-22 -- added <code> tags

Replies are listed 'Best First'.
Re: Parsing Query Strings in a file
by wog (Curate) on Jul 23, 2001 at 01:22 UTC
    The reason those values are getting longer each time appears to be because you do not clear %in (like with: %in = ();) between reads of the database. Thus, your code takes the original value1 and adds on to the version left from the previous read of the database, etc.

    (update: As HyperZonk states, explictly clearing %in would probably not be neccessary if strict were in use, though this will work if you for some bizarre silly reason can't use it.)

    General comments on your code: you should use strict and warnings. I cannot tell if you have warnings on, but I can tell that you do not have strict on. If this is a CGI script it may be worthwhile to turn on taint checking. Also, please check the return value of your open like: ((update) so you'll know if the file moves, etc.)

    open DATABASE, $Rawdata or die "opening $Rawdata: $!\n";

    It is probably better to use the constants provided with the Fcntl module for flock (since there is a slight chance they might vary from system to system.)

    use Fcntl qw(:flock); flock DATABASE, LOCK_SH or warn "Couldn't obtain shared lock: $!\n";

    Additionally, there is almost never a need to flock to unlock a file; it should be done automatically on closing. In fact, locking a file instead of just closing it can often lead to data loss when writing files due to buffering.

    You may find you can save memory by processing the file as you read it; this might be worthwhile if the file is to become very large.

    You could use the CGI module to parse your query strings like:

    my $q = CGI->new( $param_string ); foreach my $key ($q->param()) { my $value = $q->param($param); # ... }

    I cannot say whether this would be more efficient. (Though it will prevent problems if/when browsers start deliminating queries with ;. (;)

    1: Except if the original value is false -- for example, 0.

Re: Parsing Query Strings in a file
by HyperZonk (Friar) on Jul 23, 2001 at 01:08 UTC
    Briefly, your problem is that you are not using use strict. Of course, that is not very helpful by itself ...

    I have to assume that you are repeating this section of code several times during the program. The line
    if ($in{$name}) { $value = $in{$name} . ", " . $value; }
    tells the script that if the $name already exists in the hash %in that it should concatenate the newly read value onto the existing value. However, after you have been through this section of code once, $in{NAME} has a value in it from the previous pass. If %in had been localized to the block with a my, then the previous use of %in would have disappeared when that block of code went out of context.

    Now, this makes some presumptions regarding your code, such as that there is a contextual block of code around which the loop occurs. If there isn't, there probably should be.

    By the way, it looks as if you are parsing a file that saved responses from a CGI request. If this is the case, you may want to spend some time with the CGI module, which has effective, safe, and easy methods by which to do this. Using it effectively, you may even find a way to save the CGI output in a file that will require a minimum of processing when you read it back in.

    -HZ
      Thank you. Removing if ($in{$name}) { $value = $in{$name} . ", " . $value; } solved the problem. I was completely overlooking that when trying to fix this. Thanks again. Jer
Re: Parsing Query Strings in a file
by Anonymous Monk on Jul 23, 2001 at 01:03 UTC
    why not use undef?

    <code>undef $name;
    undef $amt; <code>
Re: Parsing Query Strings in a file
by CharlesClarkson (Curate) on Jul 23, 2001 at 00:50 UTC

    Post your question again. Place the code between <CODE></CODE> tags and you'll probably get more answers. Also take a look at the Writeup Formatting Tips.


    HTH,
    Charles K. Clarkson