in reply to Need help with searching flatfile and updating it.

#!/perl/bin/perl -w use CGI; $q = new CGI; for $key ( $q->param() ) { $form{$key} = $q->param($key); } $logpath = "data/browser.dat"; $temppath = "C:/Documents and Settings/Owner/My Documents/My Website/c +gi-bin/data/temp.dat"; $browser = $form{'browser'}; open (LOG, "$logpath"); @data = <LOG>; close(LOG); $not_found = 1; if($browser) { open (LOG, ">$logpath"); foreach $line(@data) { chomp($line); ($fcount,$fbrowser)= split(/\|/,$line); if ($fbrowser eq $browser) { $not_found = 0; $fcount = $fcount+1; print LOG "$fcount|$fbrowser\n"; } else { print LOG "$line\n"; } } close(LOG); if($not_found) { open (LOG,">>$logpath"); print LOG "1|$browser"; close(LOG); } } # prints out log and form to browser print "Content-type: text/html\n\n"; open (LOG, "$logpath"); @data = <LOG>; close(LOG); foreach $line(@data) { chomp($line); print "$line<br>"; } close(LOG); print <<EOT; <FORM ACTION="basic.pl" METHOD="POST"> <SELECT NAME="browser"> <OPTION VALUE="microsoft">microsoft</OPTION> <OPTION VALUE="netscape">netscape</OPTION> <OPTION VALUE="aol">aol</OPTION> <OPTION VALUE="mozilla">mozilla</OPTION> <OPTION VALUE="opera">opera</OPTION> </SELECT> <INPUT TYPE="SUBMIT" VALUE="Submit"> </FORM> EOT # If you would like to suggest a better way to sort here is the rest o +f the code. sub getBrowsers { %browse=(); open(INF,"$logpath") || print "Cannot open logs.dat file\n"; @hits= <INF>; close(INF); open(TEMP,">>$temppath") || print "Cannot open temp.dat file\n"; foreach $i (@hits) { chomp($i); ($hits,$browser)= split(/\|/,$i); for ($t=1;$t<$hits;$t++) { print TEMP "$browser\n"; } } close(TEMP); open(TEMP,"$temppath") || print "Cannot open temp.dat file\n"; @temp= <TEMP>; close(TEMP); foreach $i (@temp) { $browse{$i}++; } print <<EOT; <TABLE width="99%" cellpadding="3" cellspacing="1" border="0" bgCo +lor="#0080ff"> <TR><TD bgColor="#ccccff" height="25" colspan="2"><SPAN class="tit +le">Top Browsers</SPAN></TD></TR> EOT $max = 1; foreach $key (sort BrowserSort (keys(%browse))) { ($max > $browse{$key}) || ($max = $browse{$key}); ($max >= 401) && ($divisor = $max/401); ($max < 401) && ($multiplier = 401/$max); ($divisor) && ($width = sprintf("%0d",$browse{$key}/$divisor)); ($multiplier) && ($width = sprintf("%0d",$browse{$key} * $multipli +er)); print "<tr><td bgColor=\#FFFFFF align=left><a href=$key>$key</a><b +r><img src=../images/pix.gif width=1 height=2><br> <img src=../images/blue.gif width=$width height=10></td><td bg +Color=\#FFFFFF align=right valign=bottom>$browse{$key}</td></tr>\n"; } print "</table><p>\n"; } sub BrowserSort { $browse{$b} <=> $browse{$a}; } &getBrowsers; unlink($temppath);

Replies are listed 'Best First'.
Re: I have it working, but sorting is very greedy.
by eibwen (Friar) on Apr 25, 2005 at 05:30 UTC
    sorting is very greedy

    Have you read perlre and the Regex Tutorials? Or perhaps you were referring to something else entirely. If you were to post the specific excerpt or at the least be more specific with the regard to the problem, perhaps we can help.

      What I did was take the information in the database and split the lines, ran them through a for loop and printed them to a temp file. So if the first line was 12|netscape, then I printed netscape 12 times in the temp file, if the second line was 10|microsoft, I printed it 10 times in the temp file, and recounted them and resorted them. This is never going to work when I get to number above 1000. What I would like to do is just sort the lines in the original database numerically, on the first field, but with out rewritting them, if that's possible.

      Take the code and chop off everthing after EOT and see if you can sort the $logpath file numerically.

      #!/perl/bin/perl -w use CGI; $q = new CGI; for $key ( $q->param() ) { $form{$key} = $q->param($key); } $logpath = "data/browser.dat"; $browser = $form{'browser'}; open (LOG, "$logpath"); @data = <LOG>; close(LOG); $not_found = 1; if($browser) { open (LOG, ">$logpath"); foreach $line(@data) { chomp($line); ($fcount,$fbrowser)= split(/\|/,$line); if ($fbrowser eq $browser) { $not_found = 0; $fcount = $fcount+1; print LOG "$fcount|$fbrowser\n"; } else { print LOG "$line\n"; } } close(LOG); if($not_found) { open (LOG,">>$logpath"); print LOG "1|$browser"; close(LOG); } } # prints out log and form to browser print "Content-type: text/html\n\n"; open (LOG, "$logpath"); @data = <LOG>; close(LOG); foreach $line(@data) { chomp($line); print "$line<br>"; } close(LOG); print <<EOT; <FORM ACTION="basic.pl" METHOD="POST"> <SELECT NAME="browser"> <OPTION VALUE="microsoft">microsoft</OPTION> <OPTION VALUE="netscape">netscape</OPTION> <OPTION VALUE="aol">aol</OPTION> <OPTION VALUE="mozilla">mozilla</OPTION> <OPTION VALUE="opera">opera</OPTION> </SELECT> <INPUT TYPE="SUBMIT" VALUE="Submit"> </FORM> EOT

        Sounds like you could use a hash.

        my %browsers = (); foreach ($line) { # eg '12|netscape' $browsers{(split(/|/))[1]} = (split(/|/))[0]; } print sort { $browsers{$a} <=> $browsers{$b} } keys %browsers;

        UPDATE: Looks like it's getting late... the var in the foreach loop should be $_, not $line (fixed), thereby providing for the implicit split.