Looping using while
In the previous lesson, we learned how to branch by
using if, elsif, and else to make decisions
and execute different parts of our script based on those decisions.
There is a second major type of flow control, called looping. Looping
allows us to repeat the execution of a piece of our script. Perl provides several
ways of looping; the first we’ll learn is looping using while.
A loop can solve a fundamental problem we’ll often encounter. Suppose our script asks
the user to respond to a question by entering 1 or 2. In the
previous lesson, we learned how to test for a response
that is 1 or 2 or neither, using if,
elsif, and else. But the shortcoming of that script is that it
can finish successfully only if the user enters a correct response. When the user
enters an incorrect response—neither 1 nor 2—the
only thing the script can do is print an error message and quit. This forces the user
to run the script again, which is not very friendly.
What we need instead is a way to create a script that
that asks a question, gets the response from the user, and checks the response for
a correct answer, repeating these steps until the
response is correct. One way to accomplish this is to use a while loop.
while tests an expression to see if it’s true. If the expression
is true, then the lines of script within the curly braces following the while
clause are executed, after which Perl loops back to the same while clause.
This means that as long as the expression continues to be true, Perl continues to loop.
However, if while finds that the expression it is testing is false,
the loop is broken, the lines within the curly braces following the while clause
are not executed, and Perl moves to the next line after the while loop.
What we’ll do is initialize a flag variable to contain a value of 1.
Then we’ll use while to repeatedly test that variable to see that
it’s equal to 1. If it is, then we execute the code inside the
while loop. If it isn’t, then Perl skips the while
loop.
What we have to do to make sure this works is to change our flag variable inside the loop to a value that isn’t 1. If we never do this, then we loop forever; this is a common bug called an infinite loop.
So here’s our script:
#!/usr/bin/perl
#
# while1.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script demonstrates how to use a while loop to get a correct
# response from the user.
use warnings;
my( $flag );
my( $response );
$flag = 1;
while ( $flag == 1 )
{
# Provide a prompt and get the response.
# Note that the response is on the same line as the prompt here.
print( "Please enter 1 or 2: " );
$response = <>;
chomp( $response );
# Check for either of the two correct reponses.
# If we have the correct reponse, we change our flag variable.
# The next time we loop, $flag will not equal 1, and Perl
# won't execute the code inside the loop.
if ( $response eq "1" )
{
$flag = 0;
}
elsif ( $response eq "2" )
{
$flag = 0;
}
}
print( "Your response was $response.\n" );
Here’s what it looks like when we run this script:
> perl while1.pl Please enter 1 or 2: 1 Your response was 1. > perl while1.pl Please enter 1 or 2: 2 Your response was 2. > perl while1.pl Please enter 1 or 2: 3 Please enter 1 or 2: 4 Please enter 1 or 2: x Please enter 1 or 2: 1 Your response was 1. >
Now we can fix our investor4.pl script from the previous lesson. As a reminder, here’s that script again:
#!/usr/bin/perl
#
# investor4.pl
# 13-Jun-2004
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script asks a question that gives four choices. What happens afterwards
# depends on the choice that the user made.
use warnings;
my( $choice );
print( "Hello, investor!\n" );
print( "If you are a very conservative investor, enter 1.\n" );
print( "If you are a somewhat conservative investor, enter 2.\n" );
print( "If you are a moderate investor, enter 3.\n" );
print( "If you are an aggressive investor, enter 4.\n" );
$choice = <>;
chomp( $choice );
if ( $choice eq "1" )
{
print( "You are a very conservative investor.\n" );
print( "I recommend treasury bonds.\n" );
}
elsif ( $choice eq "2" )
{
print( "You are a somewhat conservative investor.\n" );
print( "I recommend a balanced mutual fund.\n" );
}
elsif ( $choice eq "3" )
{
print( "You are a moderative investor.\n" );
print( "I recommend a stock index mutual fund.\n" );
}
elsif ( $choice eq "4" )
{
print( "You are an aggressive investor.\n" );
print( "I recommend Internet stocks.\n" );
}
else
{
print( "$choice is an invalid response.\n" );
}
The problem with this script is that if the user enters an invalid response, the
script can’t do anything more than print an error message and quit. Now that we know
how to use a while loop, we can add a section that loops until the user
has entered a valid response. Once we have the valid response, we can branch using
if, elsif, and else to implement the choice
made by the user.
Here’s our modified script.
#!/usr/bin/perl
#
# investor5.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script asks a question that gives four choices. What happens afterwards
# depends on the choice that the user made. The script uses a while loop
# to obtain a valid response from the user.
use warnings;
my( $choice );
my( $flag );
# Provide a prompt and get the response from the user. Loop until the
# user enters a valid response.
$flag = 1;
while ( $flag == 1 )
{
# Provide the prompt.
print( "\n" );
print( "Hello, investor!\n" );
print( "If you are a very conservative investor, enter 1.\n" );
print( "If you are a somewhat conservative investor, enter 2.\n" );
print( "If you are a moderate investor, enter 3.\n" );
print( "If you are an aggressive investor, enter 4.\n" );
# Get the response from the user.
$choice = <>;
chomp( $choice );
# Check for a valid response. On a valid response, set $flag to 0.
if ( $choice eq "1" )
{
$flag = 0;
}
elsif ( $choice eq "2" )
{
$flag = 0;
}
elsif ( $choice eq "3" )
{
$flag = 0;
}
elsif ( $choice eq "4" )
{
$flag = 0;
}
else
{
print( "$choice is not a valid choice.\n" );
}
}
# We have a valid response from the user. Branch appropriately.
if ( $choice eq "1" )
{
print( "You are a very conservative investor.\n" );
print( "I recommend treasury bonds.\n" );
}
elsif ( $choice eq "2" )
{
print( "You are a somewhat conservative investor.\n" );
print( "I recommend a balanced mutual fund.\n" );
}
elsif ( $choice eq "3" )
{
print( "You are a moderative investor.\n" );
print( "I recommend a stock index mutual fund.\n" );
}
elsif ( $choice eq "4" )
{
print( "You are an aggressive investor.\n" );
print( "I recommend Internet stocks.\n" );
}
True or false
The values true and false are known in the programming world as Boolean values. Some programming languages have a variable type that can contain only Boolean values, true or false. Since Perl variables can contain any type of value, the creators of Perl have devised a way to determine the Boolean value equivalent of any type of value.
The rules are simple. A variable that contains the values 0 or ''
(empty string) or "" (empty string), or that has an
undefined value, is false. A variable that contains any other value is
true.
-
false values
-
0(zero) -
'0'and"0"(a string containing0) -
''(empty string using single quotes) or""(empty string using double quotes) - undefined value
-
-
true values
- any other value
We can use this property of Perl variables to simplify our while1.pl script slightly. As
before, we set $flag to 1. Since 1 is a defined
value that is not 0, not '', or not "",
1 is a true value. This means we can replace
while ( $flag == 1 )
with
while ( $flag )
What is critical is that when we change the value of $flag to signal that
we want to terminate looping, we have to change it to a false value. One way
to do that is to set $flag to 0.
Here is the entire script, with the change shown in bold:
#!/usr/bin/perl
#
# while2.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script demonstrates how to use a while loop to get a correct
# response from the user.
use warnings;
my( $flag );
my( $response );
$flag = 1;
while ( $flag )
{
# Provide a prompt and get the response.
# Note that the response is on the same line as the prompt here.
print( "Please enter 1 or 2: " );
$response = <>;
chomp( $response );
# Check for either of the two correct reponses.
# If we have the correct reponse, we change our flag variable.
if ( $response eq "1" )
{
$flag = 0;
}
elsif ( $response eq "2" )
{
$flag = 0;
}
}
print( "Your response was $response.\n" );
The && and || operators
We often will want to combine two or more Boolean values to make a decision in our
code. Perl provides two operators for this, the && (logical and)
and the || (logical or) operators. Here is how these operators
behave:
| 1st value | 2nd value | Result |
|---|---|---|
| T | T | T |
| T | F | F |
| F | T | F |
| F | F | F |
| 1st value | 2nd value | Result |
|---|---|---|
| T | T | T |
| T | F | T |
| F | T | T |
| F | F | F |
When we look at the truth table for the || operator, we can see that
either one or the other value has to be true, or both values have to be true, for
the result to be true. We can also see that if the first value is true, then we
don’t have to check the second value, because we know that if the first value
is true, then the result is always true. But if the first value is false, then we
have to check the second value to find out what the result will be.
The || operator is very useful when we want to check a response against
all the possible valid response values. For example, in the while2.pl script, we
have:
if ( $response eq "1" )
{
$flag = 0;
}
elsif ( $response eq "2" )
{
$flag = 0;
}
We can use the || operator to simplify this to:
if ( ( $response eq "1" ) || ( $response eq "2" ) )
{
$flag = 0;
}
Applying this change to the script, we get:
#!/usr/bin/perl
#
# while3.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script demonstrates how to use a while loop to get a correct
# response from the user.
use warnings;
my( $flag );
my( $response );
$flag = 1;
while ( $flag )
{
# Provide a prompt and get the response.
# Note that the response is on the same line as the prompt here.
print( "Please enter 1 or 2: " );
$response = <>;
chomp( $response );
# Check for either of the two correct reponses.
# If we have the correct reponse, we change our flag variable.
if ( ( $response eq "1" ) || ( $response eq "2" ) )
{
$flag = 0;
}
}
print( "Your response was $response.\n" );
We can incorporate these ideas into the investor5.pl script to simplify it. Here’s the new script, with the changes shown in bold:
#!/usr/bin/perl
#
# investor6.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This script asks a question that gives four choices. What happens afterwards
# depends on the choice that the user made. The script uses a while loop
# to obtain a valid response from the user.
use warnings;
my( $choice );
my( $flag );
# Provide a prompt and get the response from the user. Loop until the
# user enters a valid response.
$flag = 1;
while ( $flag )
{
# Provide the prompt.
print( "\n" );
print( "Hello, investor!\n" );
print( "If you are a very conservative investor, enter 1.\n" );
print( "If you are a somewhat conservative investor, enter 2.\n" );
print( "If you are a moderate investor, enter 3.\n" );
print( "If you are an aggressive investor, enter 4.\n" );
# Get the response from the user.
$choice = <>;
chomp( $choice );
# Check for a valid response. On a valid response, set $flag to 0.
if ( ( $choice eq "1" ) || ( $choice eq "2" ) ||
( $choice eq "3" ) || ( $choice eq "4" ) )
{
$flag = 0;
}
else
{
print( "$choice is not a valid choice.\n" );
}
}
# We have a valid response from the user. Branch appropriately.
if ( $choice eq "1" )
{
print( "You are a very conservative investor.\n" );
print( "I recommend treasury bonds.\n" );
}
elsif ( $choice eq "2" )
{
print( "You are a somewhat conservative investor.\n" );
print( "I recommend a balanced mutual fund.\n" );
}
elsif ( $choice eq "3" )
{
print( "You are a moderative investor.\n" );
print( "I recommend a stock index mutual fund.\n" );
}
elsif ( $choice eq "4" )
{
print( "You are an aggressive investor.\n" );
print( "I recommend Internet stocks.\n" );
}
Homework assignment
Modify the script you wrote for the homework from the last lesson. For the question
that provides multiple choices, use a while loop to check that the user has
made a valid response.
The results should look something like this, where what
the computer prints on the screen is in bold type and
what the user types is in medium type:
> perl interview2.pl Welcome to our interview! What is your name? Georgia Hi, Georgia. What is your favorite programming language? perl M&Ms come in six colors: red, orange, yellow, green, blue, and brown. Which color of M&Ms is your favorite? purple purple is not a valid response. M&Ms come in six colors: red, orange, yellow, green, blue, and brown. Which color of M&Ms is your favorite? red Your preference for red indicates that you're destined to be quite wealthy. Thanks, Georgia. It was most interesting to learn that your favorite programming language is perl and that your favorite color of M&Ms is red. Good-bye! >
Here is the script that produces this interview. Note that in this script, we use
the || operator to check the response against all the possible
valid choices.
#!/usr/bin/perl
#
# interview2.pl
# 30-Dec-2005
#
# Conrad Halling
# conrad.halling@sphaerula.com
#
# This is a demonstration script that demonstrates the following Perl concepts:
# printing strings
# printing strings containing variables
# getting input from the user
# using while for looping
# using if, elsif, and else for branching
# using the eq operator to compare two strings
use warnings;
my( $color );
my( $programmingLang );
my( $userName );
# Get the user's name.
print( "\n" );
print( "Welcome to our interview!\n\n" );
print( "What is your name?\n\n" );
$userName = <>;
chomp( $userName );
# Use the user's name in the next question.
# Get the user's favorite programming language.
print( "\n" );
print( "Hi, $userName. What is your favorite programming language?\n\n" );
$programmingLang = <>;
chomp( $programmingLang );
# Give the user a set of choices and ask for one.
# Check for a valid response.
my( $flag ) = 1;
while ( $flag )
{
# Prompt the user and get the response.
print( "\n" );
print( "M&Ms come in six colors: red, orange, yellow, green, ",
"blue, and brown.\n" );
print( "Which color of M&Ms is your favorite?\n\n" );
$color = <>;
chomp( $color );
# Check for a valid response.
if ( ( $color eq "red" ) || ( $color eq "orange" ) ||
( $color eq "yellow" ) || ( $color eq "green" ) ||
( $color eq "blue" ) || ( $color eq "brown" ) )
{
$flag = 0;
}
else
{
print( "\n" );
print( "$color is not a valid response.\n" );
}
}
print( "\n" );
# Use if elsif else to test the various possibilities for $color.
print( "Your preference for $color indicates that\n" );
if ( $color eq "red" )
{
print( "you're destined to be quite wealthy.\n" );
}
elsif ( $color eq "orange" )
{
print( "you're kind and sympathetic.\n" );
}
elsif ( $color eq "yellow" )
{
print( "you're bold and courageous.\n" );
}
elsif ( $color eq "green" )
{
print( "you're popular with your colleagues.\n" );
}
elsif ( $color eq "blue" )
{
print( "you're thoughtful and courteous.\n" );
}
elsif ( $color eq "brown" )
{
print( "you're very intelligent.\n" );
}
print( "\n" );
print( "Thanks, $userName. It was most interesting to learn that your\n" );
print( "favorite programming language is $programmingLang and that\n" );
print( "your favorite color of M&Ms is $color.\n\n" );
print( "Good-bye!\n\n" );