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

Writing a program to read in a file and let user determine string match. Below is code and error

#! /usr/bin/perl use v5.16; use warnings; ############## ## 03/14/19 ## Exercise reads from file, then lets user interactively submit matc +hing search criteria my $input_file = <STDIN>; open my $fh, '<', $input_file; chomp(my @strings = <$fh>); while (1) { print 'Please enter a pattern: '; chomp(my $pattern = <STDIN>); last if $pattern =~ /\A\s*\Z/; my @matches = eval { grep /$pattern/, @strings; }; ## end of eval if ($@) { print "Error: $@"; } else { my $count = @matches; print "There were $count matching strings:\n", map "$_\n", @matches; } print "\n"; } readline() on closed filehandle $fh at ./Chapter16_Exer1 line 11.

from this point I have entered a match pattern that I know exists in the file, but the message keeps coming back with no string found TIA the Catfish

Replies are listed 'Best First'.
Re: Working on pattern matching
by hippo (Archbishop) on Mar 14, 2019 at 16:32 UTC

    You didn't check whether open succeeded so you didn't spot that the $input_file is incorrect. See the Basic Debugging Checklist for more like this.

Re: Working on pattern matching
by nysus (Parson) on Mar 14, 2019 at 16:32 UTC
    Add in a 'die' function to see why file is not opening: open my $fh, '<', $input_file or die "Cannot open file: $!";

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar";
    $nysus = $PM . ' ' . $MCF;
    Click here if you love Perl Monks

Re: Working on pattern matching
by Marshall (Canon) on Mar 14, 2019 at 17:01 UTC
    I think you also want to get the $input_file from the command line?.
    I personally have a disdain for while(1) loops and pretty much only use them for servers or similar applications.
    I would code the loop ending condition into the while loop. If you don't like the comma operator, a logical and should work also.
    #!/usr/bin/perl use strict; use warnings; ############## ## 03/14/19 ## Exercise reads from file, then lets user interactively submit matc +hing search criteria my $input_file = shift @ARGV; open my $fh, '<', $input_file or die "unable to open $input_file for s +earching $!"; chomp(my @strings = <$fh>); my $pattern; while ( (print 'Please enter a pattern: '),$pattern=<STDIN>, $pattern +!~ /\A\s*\Z/) { chomp $pattern; my @matches = eval { grep /$pattern/, @strings; }; ## end of eval if ($@) { print "Error: $@"; } else { my $count = @matches; print "There were $count matching strings:\n", join ("\n",@matches); } print "\n"; }
    Update: you will notice that I changed a few other things. I don't see anything here that requires Perl >=5.16, so I put in "use strict;". This code should run fine on an ancient Perl. If you use some regex construct that is not available in the Perl being used, your eval will fail at run time which sounds fine to me. Instead of using a map() to add line endings to @matches, I used a join. If Perl has a special function for something, this usually works out faster and makes the code more clear than using a more general, but "heavier weight" mechanism like map. Now that I think about it, there probably isn't any need to take out the line endings in the first place which would render this point mute.

    The reason I like my while conditional is that it shows clearly what is going to cause the loop to proceed and what is going to cause it to end (blank line). Note that parens around the print statement is not a typo, they are required here in order to get the characters to the screen "mid way" through the statement. Play with the code using the parens and not using them and you will see what it does. Of course enhancements are possible, like adding an error message if the command line doesn't contain a file name. die "no input file specified!\n" unless defined ($input_file); or whatever, maybe a longer usage message? Just icing on the cake.

    Another update on style: In my opinion some of the most important "code" that you can write is "whitespace". Start the high level code at the left margin (you had it indented). Add a blank line when roughly speaking the subject/purpose changes. I put a blank line after getting the input file "ready", after getting the pattern "ready", after using the pattern. Minor quibbles can arise from this - my main point is that whitespace can increase understandability and consumes NO Mips! Consider adding blank lines at places you consider significant "thought transitions".

Re: Working on pattern matching
by thanos1983 (Parson) on Mar 14, 2019 at 16:58 UTC

    Hello catfish1116,

    Fellow Monks already told you the problem to your script. I would also to add a minor modification to possibly use a module IO::All so you do not need to bother with this minor issues and minimize your code on this part.

    Sample of modification below:

    #!/usr/bin/perl use strict; use warnings; use IO::All; use v5.16; ############## ## 03/14/19 ## Exercise reads from file, then lets user interactively submit matc +hing search criteria die "Please provide a file to process!\n" unless (defined $ARGV[0]); my @lines = io($ARGV[0])->chomp->slurp; # Chomp as you slurp while (1) { print 'Please enter a pattern: '; chomp(my $pattern = <STDIN>); last if $pattern =~ /\A\s*\Z/; my @matches = eval { grep /$pattern/, @lines; }; ## end of eval if ($@) { print "Error: $@"; } else { my $count = @matches; print "There were $count matching strings:\n", map "$_\n", @matches; } print "\n"; }

    Hope this helps, BR.

    Seeking for Perl wisdom...on the process of learning...not there...yet!