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

I'm new to Perl and I'm having trouble getting my script to print a message if an item in not found in the external file at the appropriate times. It prints the message even when the search item is found. Can someone tell me what is wrong with this code?
open (TEXTFILE, "c:/perl_programs/$fsearch") || die "\nCAN'T OPEN $fsearch\n"; print "\nEnter a string to search for: \n"; chomp ($search = <STDIN>); @line = <TEXTFILE>; string regardless of case. for (@line){ $count++; if ($_ =~ /$search/i) { print "\nLine that matched <$search> found on line #$count\n"; print "$_\n"; }} if (!($_ =~ /$search/)) { print "\nsubstring <$search> NOT found\n"; }

Replies are listed 'Best First'.
Re: problem printing message if search item is not found
by Transient (Hermit) on Jun 20, 2005 at 13:54 UTC
    You're comparing against $_ outside of the scope of the for loop, thus your regexp will always fail (unless $_ happens to be something that contains your search string).

    One way to do this is to have a "found" boolean. Set it to 0 (false) at the beginning of the program, then set it to true only if you find your string.

    After your for loop, check for the truth value of the 'found' variable and print your "not found" statement at that time.
Re: problem printing message if search item is not found
by ambrus (Abbot) on Jun 20, 2005 at 13:55 UTC

    Try something along the lines of

    ... my $match = 0; for (@line) { ... if ($_ =~ /$search/i) { print ...; $match++; } } if (!match) { print "not found"; }

    Read Transient's reply above, he is right. His "found" variable is called $match here. A similar trick is used in this program, where the flag $found_any is used in the same manner, and later it is used to generate the exit code.

Re: problem printing message if search item is not found
by holli (Abbot) on Jun 20, 2005 at 14:00 UTC
    That is because this code:
    if (!($_ =~ /$search/)) { print "\nsubstring <$search> NOT found\n"; }
    is executed outside the loop. So it will print the message always, except for the case when the last line contains the searchword. You have to use a flag.
    my $found; my $counter; for (@line) { $counter++; if ($_ =~ /$search/i) { print "\nLine that matched <$search> found on line $counter\n"; print "$_\n"; $found++; } } if ( $found ) { print "$count found words total\n"; } else { print "\nsubstring <$search> NOT found\n"; }


    holli, /regexed monk/
Re: problem printing message if search item is not found
by cbrandtbuffalo (Deacon) on Jun 20, 2005 at 14:39 UTC
    Since you are new to Perl and currently forming some habits, consider adding the following to your scripts:
    use strict; use warnings;
    Over the long run these optional settings will help point out many small problems in your code. They wouldn't have helped you with your current question, but may head off some future ones.
      Thought it might be helpful to see a rewrite of the code. ;)

      Just cleaned up a bit, and added use strict; and use warnings; and a little bit of error handling.
      #!/usr/bin/perl use strict; use warnings; my $fsearch = 'file.txt'; open (TEXTFILE, 'c:/perl_programs/' . $fsearch) or die "CAN'T OPEN $fs +earch: $^E\n"; print "Enter a string to search for: "; chomp (my $search = <STDIN>); my @line = <TEXTFILE>; my $count = 0; foreach (@line){ $count++; if ($_ =~ /$search/i) { print "\nLine that matched <$search> found on line #$count\n"; print "$_\n"; } } if (!$count) { print "\nsubstring <$search> NOT found\n"; }
Re: problem printing message if search item is not found
by thundergnat (Deacon) on Jun 20, 2005 at 17:55 UTC

    Besides the things already pointed out, there are some other issues with your script which may be problematic.

    You are slurping the entire file into an array all at once. That isn't a problem for small files but if they start to hit a couple of MB, it may cause heavy swapping and out-of-memory errors. Better to process the file a bit at a time.

    Also, since the file is being searched line by line, you can't search on strings that cross newlines.

    A fairly simple fix to both of these is to process the file in paragraph mode. (What I am using below isn't true paragraph mode since that makes it much harder to keep track of line numbers, but it is a good approximation.)

    ############################################################### use warnings; use strict; my $fsearch = 'filename.txt'; print "\nEnter a string to search for:>"; my $search = <STDIN>; chomp $search; open my $TEXTFILE, '<', $fsearch or die "\nCan't open $fsearch $!\n"; $/ = "\n\n"; my ($linecount, $count) = (0,0); while (my $paragraph = <$TEXTFILE>) { while ($paragraph =~ /([^\n]*?($search)([^\n]*))/mig) { $count++; my $linenumber = $linecount + substr($paragraph, 0, $-[0]) =~ tr/\n/\n/ + 1; print "\n'$2' found on line #$linenumber\n\n"; print "$1\n", '-' x 79; pos $paragraph -= length $3; } $linecount += $paragraph =~ tr/\n/\n/; } print "\nThe string '$search' was ", ($count ? "found $count times" : "not found"), " in $fsearch"; ###############################################################

    Notice that since the search term is not quotameta-ed you can search for strings like "\bto[ \n]be\b" (to be across a newline) or "\b\w*gh\w*\b" (words containing 'gh') as well as absolute strings like "again" or "match".