Link to home
Start Free TrialLog in
Avatar of saskia
saskia

asked on

foreach and faster problem

I use the script below to build a small database of 100 records.
Then they are read out again and each record will be checked if
a value of the array @words is present, if so the
record will be printed.

The problem is that the 'foreach $x (@words){' line doesn't go through
each character/word of @words. I tried it with the parameter sentence 'hello,0,c'.
When I trie to print out the $x value it gives me the value 0 instead of the
current value of @words.

- How can I fix this problem ?

- Also I must make this script faster (the part between the stopwatch lines)
  So I hope someone can alter this script to produce faster output.



#!/usr/bin/perl
use CGI;
use DB_File ;
$q=new CGI;
print "Content-type: text/html\n\n";
$sentence=$q->param('sentence');
@words=split(",",$sentence);

unlink "fruit" ;
tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH or die "Cannot open file 'fruit': $!\n";
for ($xx=1; $xx<100; $xx++){
    $h{$xx} = 'CIS100@é@01@é@Intro@é@to Computing@é@8';
}untie %h ;


$stopwatch_aan=(times)[0];
tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH or die "Cannot open file 'fruit': $!\n";
while (($h,$line)=each %h){
@line=split('@é@',$line);

foreach $x (@words){
if (grep /$x/,@line){
($Course,$Section,$Title,$Tiles)=split('@é@',$line);
print qq{Record=$h<br>Course=$Course<br>Section=$Section<br>Title=$Title<br>Tiles=$Tiles<br>$x<br><br>};
}}

}
$stopwatch_uit=(times)[0];

print qq{<hr>};
printf "search time: %.8f seconds\n",$stopwatch_uit-$stopwatch_aan;


Avatar of harris_c
harris_c
Flag of Philippines image

The problem is that the 'foreach $x (@words){' line doesn't go through
each character/word of @words. I tried it with the parameter sentence 'hello,0,c'.
When I trie to print out the $x value it gives me the value 0 instead of the
current value of @words.

==> well, actually it does.
foreach $x (@words) {
     print "\$x=$x\n";        #<=== insert this to verify
if (grep /$x/,@line){
...

Also, why use grep and not plain m//?

hec",)
Avatar of inq123
inq123

First of all, the foreach should work.  Are you sure you passed "hello,0,c" correctly?  Another thing is did you notice you mixed @line and $line?

A couple suggestions to speed up:
1. Instead of @words = split(/,/, $sentence), you should do $sentence =~ s/,/\|/g;  Then get rid of foreach, instead use grep /$sentence/, @line  That'd definitely be faster.
2. For last files, get rid of tie, foreach, grep altogether and instead use open(IN, "grep $sentence fruit |"), that'll definitely be faster for larger files.
SOLUTION
Avatar of FishMonger
FishMonger
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of saskia

ASKER

thank you so far. I'll take a look at your comment and give away the points later this week.
Avatar of saskia

ASKER

inq123
Can you give me an example (some code) based on my script with the line:
open(IN, "grep $sentence fruit |")
in it ?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of saskia

ASKER

inq123

The first two scripts work perfectly, though the second script takes about 8 seconds to complete (using perlwiz on a pentium 3 655 mhz.)

When I try to test the third script I receive the following error:
Insecure $ENV{PATH} while running -T switch at line 11
(line 11= the open(IN, "egrep '$sentence' fruit |"); )
What is wrong with that line ?

Fishmonger, still among us ?


YES, I'm still here but I've been side tracked in multiple directions.  Tomarrow, when my head clears of the all the alcohol that I've drank, I'll see what input I can give.
Avatar of saskia

ASKER

;)) ok, thanks
When running the scipt under taint mode, Perl keeps track of data that comes from the user (or external command) to avoid doing anything insecure with it.  In this case, you're inheriting $ENV{PATH} and calling an external program (egrep) which Perl's taint mode says is insecure.  You could add a couple of lines at the beginning of the script which will allow you to run the script in a more secure environment.

$ENV{PATH} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV'};
If you need/want more detailed info on the use and effects of Perls taint mode, I'd recommend 'CGI Programming with Perl' by Scott Guelich, Shishir Gundavaram & Gunther Birznieks and/or 'Programming Perl' by Larry Wall, Tom Christiansen, & Jon Orwant.
Avatar of saskia

ASKER

Ok, thank you all for contributing. I'll close the question. I'm gonna use the second script inq123 gave me.