SPUG: ifs and whiles and hashes...

Ken McGlothlen mcglk at serv.net
Wed Aug 18 19:18:37 CDT 1999


Ryan Forsythe <ryan2 at webrocket.net> writes:

| i'm writing a program which opens a text file, searches each line, and
| extracts data from it and sticks it in a hash...well, that's what it's
| supposed to do.  here's a simplification of the loop i'm having problems
| with:
| 
| while (defined($dbaseLine = <DATABASE>))  {
| 
| 	#code here...
| 
| 	if ($dbaseLine =~ m/^\"(?:.*)\",\"(.*)\",\"(.*)\"/)  {
| 		
| 		$hash{'key1'} = $1;
| 		$hash{'key2'} = $2;
| 		#etc...
| 	}  else  {
| 		next;
| 	}
| }
| 
| however, my program has 26 of these '\"(.*)\",' in the 'if ($dbaseLine...'
| test.  when i run it, it assigns the $dbaseLine variable okay, but when it
| gets to that if test, it locks up and i watch perl's cpu time go up to 99%.
| i'm assuming it's getting in an infinite loop, but why?  i don't understand
| how an if can cause and infinite loop, especially when it doesn't affect the
| test variable of the while it's wrapped in (if that makes any sense to
| anybody :))

Well, it's not the "if" statement itself---it's the matching process.  Perl is
attempting all sorts of possible combinations in this case to figure out if the
regexp fits (I posted a similar problem to this list just the other day).

You might do well to replace the .* expression with [^"]*, which would at least
stop at the first non-quote character.

However, what I would probably do in this case is try to figure out what
actually makes a line qualify as a $dbaseLine.  What are you trying to exclude?

If all you're worried about is blank lines, that's easy enough to handle:

	while( defined( $dbaseLine = <DATABASE> ) ) {
		chomp( $dbaseLine );
		next  if( $dbaseLine eq "" );
		...
	}

for example.

As far as handling the breaking up of the variable itself, I might recommend
going with something else that will work a lot faster.  For example:

	$dbaseLine = s/^"//;		# Trim opening quote.
	$dbaseLine = s/"$//;		# And the trailing one.
	@vals = split( /","/, $dbaseLine )	# Break it up.
	$count = 0;
	for( @vals ) {
		++$count;
		$hash{"key$count"} = $_;
	}

More code, but avoids the endless attempts to match the complex regex.

							---Ken

 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    POST TO: spug-list at pm.org        PROBLEMS: owner-spug-list at pm.org
 Seattle Perl Users Group (SPUG) Home Page: http://www.halcyon.com/spug/
 SUBSCRIBE/UNSUBSCRIBE: Replace ACTION below by subscribe or unsubscribe
        Email to majordomo at pm.org: ACTION spug-list your_address





More information about the spug-list mailing list