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

Hello Monks I am trying to create a perl program only using hashes and loops that performs an address book function. you can add, delete, print or end program. I have started but I am having a problem in my code below the user is given a menu I have created the code for the add address as seen, after the user enters the name and address it is suppose to reshow the menu an run again, as seen below, but when user enters add again in the second menu the program quits. Any help here?
#!/usr/bin/perl -w use strict; use warnings; my $input; my $name; my %directory = (); print " Welcome to your own Personal Address Book!\n"; print " What would you like to do?\n"; print "add Add An Entry del Delete An Entry prn Print all Entries end End Porgram Choice: \n"; chomp ($input = <>); for ($input eq "end") { if ($input eq "add") { print "Enter the Name you would like to add: \n"; chomp ($name = <>); for ($input eq "add") { print "Enter an Address for $name\n"; chomp (my $address = <>); $directory{$name} = $address; print "add Add An Entry del Delete An Entry prn Print all Entries end End Porgram Choice: \n"; chomp ($input = <>); } } elsif ($input eq "prn") { print "These are the people in your address book\n"; my @completed = keys %directory; foreach my $who (@completed) { printf "%15s Name: Address: %s\n", $who, $directory{$who}; } last; } }

Replies are listed 'Best First'.
Re: Problem with loops
by toolic (Bishop) on Nov 26, 2011 at 00:50 UTC
      thank you that worked, I had tried that prior but I had the for and the while flipped around so thats why I reverted back to the to for's
Re: Problem with loops
by chromatic (Archbishop) on Nov 26, 2011 at 00:46 UTC

    What do you expect this to do?

    for ($input eq "end")

    for takes a list of values. $input eq "end" is an expression; for will loop over whatever that expression produces.


    Improve your skills with Modern Perl: the free book.

      well I am trying to create it so after the first time the user enters the name and address the program presents the menu again so that they can add print delete or whatever. I thought a loop was needed a second time to know when to get out, is their something else I should be doing?
        Certainly you'll need a loop, but if you want the menu to be shown repeatedly, you have to print it inside the loop.
Re: Problem with loops
by JavaFan (Canon) on Nov 26, 2011 at 00:52 UTC
    for ($input eq "end")
    Really? It runs the loop once, setting $_ to 1 or "" depending on $input, but you aren't using $_ in your loop. It probably doesn't do what you expect it to do.

    As for the second choice - afterwards you read in the input, assign it to $input, then fall out of the loop.

    I'd do something like:

    while (1) { local $| = 1; print "add, del, prn, end? "; my $answer = <>; chomp $answer; if ($answer eq "add") { ... } elsif ($answer eq "del") { ... } elsif ($answer eq "prn") { ... } elsif ($answer eq "end") {last;} else {print "Unknown command '$answer'\n"} }
      well it works for the add part, but now to add the print function and delete function, and maybe I haven't tested it enough, will keep your response in mine though
Re: Problem with loops
by TJPride (Pilgrim) on Nov 26, 2011 at 06:01 UTC
    use strict; use warnings; my ($inp, $name, $address, %directory); print "Welcome to your own Personal Address Book!\n"; while (1) { while (1) { print " What would you like to do?\n ADD Add An Entry DEL Delete An Entry PRN Print All Entries END End Program\n\n"; $inp = uc getInput(''); last if $inp eq 'ADD' || $inp eq 'DEL' || $inp eq 'PRN'; exit if $inp eq 'END'; } print "\n"; if ($inp eq 'ADD') { $name = getInput('Enter a name to add'); $address = getInput('Enter the corresponding address'); $directory{$name} = $address; } elsif ($inp eq 'DEL') { $name = getInput('Enter a name to remove'); delete $directory{$name}; } else { print "These are the people in your address book:\n\n"; print "$_\t\t$directory{$_}\n" for sort keys %directory; } } sub getInput { my $inp; while (1) { print "$_[0]: "; chomp($inp = <STDIN>); return $inp if $inp; } }
Re: Problem with loops
by Marshall (Canon) on Nov 27, 2011 at 00:44 UTC
    This smells like homework, but I'll help you get started...
    The main problem is faulty loop construction.

    We need a loop that will end when the user types "end" -( I also added "quit" which would be a more normal "ending command"). So, make that "ending condition" appear prominently as a loop condition. Below I used a "while" loop.

    I like to use the comma operator to put the prompting part also inside the loop condition. You don't have to do that, but this avoids having to put the "command prompt" in more than one place.

    Most of these things use a short one line prompt rather than repeating all of this long verbiage for each user input. You can add a help function if you like.

    Normal user input rules allow leading and trailing white space on a user inputted line. And a blank line is normally just a re-prompt (not an error).

    I would use subroutines for the functions. This leads to a very clean looking main loop. I would not worry about cramming things together in the minimum number of lines - make it look nice and easy to understand.

    Update:

    I see that %directory is not the best name. I used that because that is what you had. %addressBook would be better, as would print_addressBook() instead of print_directory(). Think about good names - this makes a lot of difference!

    Perl gets a reputation as "write once" code when we get too cryptic. It doesn't have to be that way! And often these cryptic looking "one-liners" run slower than a more verbose formulation.

    I would argue that code like the below is understandable - at least at a high level - to someone skilled in the art of programming even if they don't understand every detail of the Perl syntax.

    #!/usr/bin/perl -w use strict; print " Welcome to your own Personal Address Book!\n"; my $explain_text = " Command are: add Add An Entry del Delete An Entry prn Print all Entries end End Program quit Also Ends program "; my $short_prompt = "add,del,prn or quit: "; my $input; my %directory=(); print $explain_text; #don't keep printing this long stuff while ( ($input=prompt_for_input($short_prompt)), $input !~ /\s*end|qu +it\s*$/i) { next if $input =~ /^\s*$/; # re-prompt on blank lines # this is not an error! if ($input =~ /^\s*add\s*$/) { add_entry(); } elsif ($input =~ /^\s*del\s*$/) { delete_entry(); } elsif ($input =~ /^\s*prn\s*$/) { print_directory(); } else { print "illegal command!\n"; } } sub prompt_for_input { my $message = shift; print $message; my $input = <>; $input =~ s/^\s*//; # no leading spaces $input =~ s/\s*$//; # no trailing spaces return $input; } sub add_entry { my $name = prompt_for_input ("Enter the Name you would like to add: + "); my $address = prompt_for_input ("Enter an Address for $name: "); $directory{$name} = $address; } sub delete_entry { print "some code to get name to delete goes here\n"; } sub print_directory { print "These are the people in your address book:\n"; printf "%-15s %s\n", "Name", "Address"; foreach my $who (sort keys %directory) { printf "%-15s %s\n", $who, $directory{$who}; } print "\n"; }