Reputation: 103
I am trying to make a program that simulates a line at a grocery storye. if a is entered, it allows for users to add names. if c is entered, it simulates a person leaving the line. if p is entered, it prints the list of names. if q is entered, it quits.
my code just results in an infinite loop and I am not sure why. Every time I try and enter in values, it just reads invalid input and wont exit. I am not sure if the other stuff is working or not but that is not what I need help with.
$choice="";
$name;
@line=();
print "\n";
print "Choose an option:\n";
print "a: Add person to end of line\n";
print "c: Call the next person in line\n";
print "p: Print the list of people in line\n";
print "q: Quit\n";
print "\n";
while ($choice ne "q") {
print "Your choice:";
$choice = <>;
print "\n";
if($choice eq "a") {
print "Enter name:";
$name = <>;
push(@line,$name);
}
elsif ($choice eq "c") {
shift(@line);
}
elsif ($choice eq "p") {
for ($i=0;$i<=scalar(@line);$i++) {
print (@line[$i]);
}
}
elsif ($choice eq "q") {
exit;
}
else {
print "Invalid option";
}
}
Upvotes: 0
Views: 130
Reputation: 29844
chomp
is a good idea, but sometimes it is not enough. This is input, so sometimes you want the wide-acceptance pattern. As illustrated by the other two posts, your pattern is too narrow, it does not allow for the line-ending character at the end of input.
However, isn't the character with an extraneous space afterwards, just about equivalent? So perhaps you want to do this:
my $line = <>;
my ( $choice ) = $line =~ m/^\s*([acqp])\s*$/;
And if you want to accept letters of both cases, you simply can add an i
flag at the end of the match expression (m//
), and probably a map command to lc
(lowercase) the result:
my $line = <>;
my ( $choice ) = map {; lc } $line =~ m/^\s*([acqp])\s*$/i;
You could also decide that you don't care about fat-fingers and make the match expression like so:
m/^\s*([acqp])(?:\W.*)?$/i
Which means at least one non-word character--if any characters--before the line-break.
I practice wide acceptance on input. It's a reason no one will ever be exasperated at a date entry field in one of my applications. My date fields don't try to pretend that they cannot ascertain date expressions unless you include a leading 0 or follow some MM/DD pattern, for example. (and a single number between 1 and 31 defaults to the current month or most recent month or next month depending on date logic (reporting? planning?) and dates passed or left in the month). Just advice on input, that's all.
Upvotes: 1
Reputation: 5279
As @stark has correctly pointed out, the main issue with your loop is that you're not removing the newline after getting your input from STDIN. So, $choice will never match your options and you will never break out of the loop. Try changing:
print "Your choice:";
$choice = <>;
to
print "Your choice:";
$choice = <STDIN>;
chomp $choice;
Notice that you'll need to chomp $choice
in order to remove the newline before you do your string comparison.
Also, try writing your scripts with "use warnings" and "use strict". This will pick up a lot of little errors you may not otherwise have noticed. For example, your script might look something like this:
#!/usr/bin/env perl
use strict;
use warnings;
my $choice = "";
my $name;
my @line = ();
print "\n";
print "Choose an option:\n";
print "a: Add person to end of line\n";
print "c: Call the next person in line\n";
print "p: Print the list of people in line\n";
print "q: Quit\n";
print "\n";
while ( $choice ne "q" ) {
print "Your choice:";
$choice = <STDIN>;
chomp $choice;
print "\n";
if ( $choice eq "a" ) {
print "Enter name:";
$name = <>;
push( @line, $name );
}
elsif ( $choice eq "c" ) {
shift( @line );
}
elsif ( $choice eq "p" ) {
for ( my $i = 0; $i <= scalar( @line ); $i++ ) {
print( $line[$i] );
}
}
elsif ( $choice eq "q" ) {
exit;
}
else {
print "Invalid option";
}
}
Upvotes: 4
Reputation: 13189
The "<>" function returns a line of input, not a character. You need to remove the newline at the end.
Upvotes: 1