Search code examples
perlchomp

Need something like open OR DIE except with chomp


I'm fairly new to coding and I need a fail statement to print out as if it were an or die.

Part of my code for an example:

    print "Please enter the name of the file to search:";
    chomp (my $filename=<STDIN>) or die "No such file exists. Exiting program. Please try again."\n;

    print "Enter a word to search for:";
    chomp (my $word=<STDIN>);

I need it to do it for both of these print/chomp statements. Is there anyway to just add on to this?

Whole program:

#!/usr/bin/perl -w

use strict;

print "Welcome to the word frequency calculator.\n";
print "This program prompts the user for a file to open, \n";
print "then it prompts for a word to search for in that file,\n";
print "finally the frequency of the word is displayed.\n";
print " \n";

print "Please enter the name of the file to search:";
while (<>){
        print;
}

print "Enter a word to search for:";
chomp( my $input = <STDIN> );

my $filename = <STDIN>;

my$ctr=0;
foreach( $filename ) {
        if ( /\b$input\b/ ) {
                $ctr++;
        }
}
print "Freq: $ctr\n";

exit;

Solution

  • You don't need to test the filehandle read <> for success. See I/O Operators in perlop. When it has nothing to read it returns an undef, which is precisely what you want so your code knows when to stop reading.

    As for removing the newline, you want to chomp separately anyway. Otherwise, once the read does return an undef you'd chomp on an undefined variable, triggering a warning.

    Normally, with a filehandle $fh opened on some resource, you'd do

    while (my $line = <$fh>) {
        chomp $line;
        # process/store input as it comes ...
    }
    

    This can be STDIN as well. If it is certainly just one line

    my $filename = <STDIN>;
    chomp $filename;
    

    You don't need to test chomp against failure either. Note that it returns the number of characters that it removed, so if there was no $/ (newline typically) it legitimately returns 0.

    To add, it is a very good practice to always test! As a part of that mindset, please make sure to always use warnings;, and I also strongly recommend coding with use strict;.


    Update to a significant question edit

    In the first while loop you do not store the filename anywhere. Given the greeting that is printed, instead of that loop you should just read the filename. Then you read the word to search for.

    # print greeting
    
    my $filename = <STDIN>;
    chomp $filename;
    
    my $input = <STDIN>;
    chomp $input;
    

    However, then we get to the bigger problem: you need to open the file, and only then can you go through it line by line and search for the word. This is where you need the test. See the linked doc page and the tutorial perlopentut. First check whether a file with that name exists.

    if (not -e $filename) {
        print "No file $filename. Please try again.\n";
        exit;
    }
    
    open my $fh, '<', $filename  or die "Can't open $filename: $!";
    
    my $word_count = 0;
    while (my $line = <$fh>) 
    {
        # Now search for the word on a line
        while ($line =~ /\b$input\b/g) {
            $word_count++;
        }
    }
    close $fh  or die "Can't close filehandle: $!";
    

    The -e above is one of the file-tests, this one checking whether the given file exists. See the doc page for file-tests (-X). In the code above we just exit with a message, but you may want to print the message prompting the user to enter another name, in a loop.

    We use while and the /g modifier in regex to find all occurencies of the word on a line.

    I'd like to also strongly suggest to always start your programs with

    use warnings 'all';
    use strict;