Beginning Perl Lesson 4

Table of Contents

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.

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:

Truth table for && operator
1st value 2nd value Result
T T T
T F F
F T F
F F F
Truth table for || operator
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" );