Chapter 7. If Only, Unconditionally, Forever

Image

By the end of this chapter, you will be able to read and write the following Perl code:

use warnings;
use feature qw(say);
my %guests=("Joe"=>"pizza",
            "Medhi"=>"veggies",
            "Dat"=>"rice",
            "Vipul"=>"meat",
            "Anna"=>"sandwiches",
            "Peter"=>"dessert",
            );
my $place="Golden Gate Park";
my $when = "Tomorrow, noon";
foreach (keys %guests){
   if ($_ eq "Anna"){ next; }
   my $message=<<EOF;
   Hello, $_. Please join me at the $place at $when for
   a picnic. You will bring $guests{$_} and I'll bring
   the drinks. RSPV if you can't make it.
   Later,
   [email protected]
EOF
   say $message;
}

7.1 Control Structures, Blocks, and Compound Statements

People plan their lives by making decisions, and so do programs. Figure 7.1 is a flow chart. A flow chart is defined as a pictorial representation of how to plan the stages of a program. It helps you to visualize what decisions need to be made to accomplish a task. According to computer science books, a good language allows you to control the flow of your program in three ways:

• Execute a sequence of statements.

• Based on the results of a test, branch to an alternative sequence of statements.

• Repeat a sequence of statements until some condition is met.

Image

Figure 7.1 A flow chart.

So far, we have seen script examples that are linear in structure; that is, simple statements that are executed in sequence, one after the other. Control structures, such as branching and looping statements, allow the flow of the program’s control to change depending on some conditional expression.

The decision-making constructs (if, if/else, if/elsif/else, unless, and so forth) contain a control expression that determines whether a block of statements will be executed.

The looping constructs (while, until, for, foreach) allow the program to repetitively execute a statement block until some condition is satisfied.

A compound statement, or block, consists of a group of statements surrounded by curly braces and usually follows an if, else, while, or for construct. But unlike C, where curly braces are not always required, Perl requires them, even with one statement when that statement comes after the if, else, while, and so forth. The conditional modifiers, discussed in Chapter 8, “Regular Expressions—Pattern Matching,” can be used when a condition is evaluated within a single statement.

7.1.1 Decision Making—Conditional Constructs

if and unless Statements

The if and unless constructs are followed by an expression surrounded by parentheses and followed by a block of one more statements. The block of statements are always enclosed in curly braces.

An if statement is a conditional statement. It allows you to test an expression and, based on the results of the test, make a decision. The expression is enclosed in parentheses and Perl evaluates the expression in a string context. If the string is not empty, the expression is true; otherwise, the expression is false. If the expression is evaluated to be true, the next statement block is executed; if the condition is false, Perl will skip the block associated with the expression and go on to the next executable statement within the script.

The unless statement is constructed exactly the same as the if statement; the results of the test are simply reversed. If the expression is evaluated to be false, the next statement block is executed; if the expression is evaluated to be true, Perl will ignore the block of statements controlled by the expression.

The if Construct

The if statement consists of the keyword if, followed by a conditional expression, followed by a block of one or more statements enclosed in curly braces. Each statement within the block is terminated with a semicolon (;). The block of statements collectively is often called a compound statement. Make sure when you are testing strings that you use the string operators shown in Table 6.7, “Equality Operators and String Values,” and that if testing numbers, you use the numeric operators also shown in Table 6.6, “Equality Operators and Numeric Values.” Perl converts strings and numbers to conform to what the operator expects, so be careful. A test such as “yes” == “no” is incorrect. It should be “yes” eq “no”.

The if/else Construct

Another form of the if statement is the if/else construct. This construct allows for a two-way decision. If the first conditional expression following the if keyword is true, the block of statements following the if are executed. Otherwise, if the conditional expression following the if keyword is false, control branches to the else, and the block of statements following the else are executed. The else statement is never an independent statement. It must follow an if statement. When the if statements are nested within other if statements, the else statement is associated with the closest previous if statement. (Review the ternary operator in Section 6.3.4, “Conditional Operators,” for an alternative to a simple if/else block.)

The if/elsif/else Construct

Yet another form of the if statement is the if/elsif/else construct. This construct provides a multiway decision structure. If the first conditional expression following the if keyword is true, the block of statements following the if is executed. Otherwise, the first elsif statement is tested. If the conditional expression following the first elsif is false, the next elsif is tested, and so forth. If all of the conditional expressions following the elsifs are false, the block after the else is executed; this is the default action.

The unless Construct

The unless statement is similar to the if statement, except that the control expression after the unless is tested for the reverse condition; that is, if the conditional expression following the unless is false, the statement block is executed.

The unless/else and unless/elsif behave in the same way as the if/else and if /elsif statements with the same reversed test as previously stated.

7.2 Statement Modifiers and Simple Statements

In English, a modifier is an adjective or adverb; for example:

He ran.  (without an adverb)

He ran quickly.  (with an adverb)

Perl modifiers are like adverbs in that they modify the way a function behaves, and like most adverbs, they are tacked onto the end of a statement. They allow you to evaluate a statement based on some condition, and are simpler to use than the full-blown conditional construct. The modifier and its expression are always terminated with a semicolon. Perl provides the following modifiers. We’ll discuss the conditional modifiers now and the loop modifiers later.

if

unless

while

until

foreach

7.2.1 The if Modifier

The if modifier is used to control a simple statement consisting of two expressions. If Expression1 is true, Expression2 is executed. Expression2 cannot contain multiple statements. If it does, then you will need to use the traditional conditional with a block of statements, such as, if (Expression1 ){ Statement1; Statement2, and so forth }.

7.2.2 The unless Modifier

The unless modifier is used to control a simple statement consisting of two expressions. If Expression1 is false, Expression2 is executed. Like the if modifier, unless is placed at the end of the statement.

7.3 Repetition with Loops

Sometimes, you may want to repeat a statement or group of statements until some condition is met; for example, continue to ask the user a question until he gives the correct response, or you may want to create a timer that counts down from 10 to 0, or you may want to modify each item in a list, until you reach the end of the list. This is where loops come in. They are used to execute a segment of code repeatedly. Perl’s basic looping constructs are as follows:

while

until

for

foreach

Each loop is followed by a block of statements enclosed in curly braces.

7.3.1 The while Loop

The while statement executes the block as long as the control expression after the while is true. An expression is true if it evaluates to nonzero (true); while(1) is always true and loops forever. An expression is false if it evaluates to zero; while(0) is false and never loops. See Figure 7.2.

Image

Figure 7.2 How the while loop works.

7.3.2 The until Loop

The until statement executes the block as long as the control expression after the until is false. When the expression evaluates to true, the loop exits. See Figure 7.3.

Image

Figure 7.3 How the until loop works.

7.3.3 The do/while and do/until Loops

The do/while or do/until loops evaluate the conditional expression for true and false just as in the while and until loop statements. However, the expression is not evaluated until after the block is executed at least once.

7.3.4 The for Loop (The Three-Part Loop)

The for statement is like the for loop in C. The for keyword is followed by three expressions separated by semicolons and enclosed within parentheses. You can omit any or all of the expressions, but not the two semicolons. The first expression is used to set the initial value of variables, the second expression is used to test whether the loop should continue or stop, and the third expression updates the loop variables. See Figure 7.4.

Image

Figure 7.4 How the three-part for loop works.

7.3.5 The foreach (for) Loop

If you need to iterate through an array or hash such as a list of files, IP or email addresses, keys, values from a hash, and so forth, then the foreach loop, as its name implies, is a control structure designed just for you.

The foreach loop (a synonym for for) iterates over each element in the parenthesized list or an array, aliasing each element of the list to a scalar variable, one after the other, until the end of the list.

The VARIABLE is local to the foreach block. It will regain its former value when the loop is exited. Any changes made when assigning values to VARIABLE will, in turn, affect the individual elements of the array. If VARIABLE is not present, the $_ special scalar variable is implicitly used.

7.4 Looping Modifiers

In this section we will discuss looping modifiers and various control statements you can use for increased file manipulation.

7.4.1 The while Modifier

The while modifier repeatedly executes the second expression as long as the first expression is true.

7.4.2 The foreach Modifier

The foreach modifier evaluates once for each element in its list, with $_ aliased to each element of the list, in turn.

7.4.3 Loop Control

To interrupt the normal flow of control within a loop, Perl provides labels and simple control statements. These statements are used for controlling a loop when some condition is reached; that is, the control is transferred directly to either the bottom or the top of the loop, skipping any statements that follow the control statement condition.

Labels

Labels are optional but you can use them to control the flow of a loop. (Note that you can attach them to any statement, not just loops.) By themselves, labels do nothing. They are used with the loop control modifiers, listed next. A block by itself, whether or not it has a label, is equivalent to a loop that executes only once. If labels are capitalized, they will not be confused with reserved words.

The next statement restarts the next iteration of the loop, skipping over the rest of the statements in the loop and reevaluating the loop expression, like a C, awk, or shell continue statement. Since a block is a loop that iterates once, you can use next (with a continue block, if provided) to exit the block early.

The last statement leaves or breaks out of a loop and is like the break statement in C, awk, and shell. Since a block is a loop that iterates once, you can use last to break out of a block.

The redo statement restarts the block without evaluating the loop expression again.

The continue block is executed just before the conditional expression is about to be evaluated again.

The goto statement, although frowned upon by most programmers, is allowed in Perl programs. It takes a label as its argument and jumps to the label when the goto statement is executed. The label can be anywhere in your script but does not work when it appears inside a do statement or within a subroutine.

The redo and goto Statements

A block is like a loop that executes once. You can label a block. The redo statement causes control to start at the top of the innermost or labeled block without reevaluating the loop expression if there is one (similar to a goto). The goto finds the label and resumes execution at that point. It can go almost anywhere within the script scope, including getting out of subroutines.

Nested Loops and Labels

A loop within a loop is a nested loop. The outside loop is initialized and tested, the inside loop then iterates completely through all of its cycles, and the outside loop starts again where it left off. The inside loop moves faster than the outside loop.

You can nest loops as deeply as you wish, but there are times when it is necessary to terminate the loop when some condition is met. Normally, if you use loop-control statements, such as next and last, the control is directed to the innermost loop. There are times when it might be necessary to switch control to some outer loop. This is accomplished by using labels.

By prefixing a loop with a label, you can control the flow of the program with last, next, and redo statements. Labeling a loop is like giving the loop its own name.

When a label is omitted, the loop-control statements next, last, and redo, reference the innermost loop. When branching out of a nested loop to an outer loop, labels may precede the loop statement.

The continue Statement

When followed by a block, the continue statement acts as a flow-control statement. When a continue block is attached to the end of a while or foreach block, it is always executed just before the loop conditional is about to be evaluated again, just like the third part of a for loop, and even if there is a next statement within the loop, control will go to the continue block before re-evaluating the loop condition again.

7.4.4 The switch Statement (given/when)

A switch statement is another type of control statement similar to if/elsif/else but evaluates an expression by matching the expression to a set of case labels. When a match is found, program control is transferred to that block where the expression matched the label value.

A switch statement in the C language, Java, PHP, and so forth, is designed like so:

switch (expression) {
    case value1 :
        /* statements */
        break;
    case value2 :
        /* statements */
        break;
    case value3 :
        /* statements */
        break;
    default:
        /* statements */
        break;
}

Although the switch/case mechanism is a common control structure provided by most modern programming languages, it is not available in core Perl. You can achieve the same goal in Perl with the traditional if/elsif/else constructs or by creating labeled blocks, as shown next. Since a block (labeled or not) is equivalent to a loop that executes once, and you can use loop control statements, such as last, next, and redo, within this block, you can create a phony switch statement by adding a do block, which will execute a sequence of commands within the block (see Example 7.32). Since 5.10.1, the experimental feature from Perl 6 is available enabling a whole new way of creating a switch-style statement with new Perl constructs: given and when (see Examples 7.33 and 7.34).

The switch Feature (given/when/say)

Starting with Perl 5.10.1 and beyond, you can use the experimental switch feature which enables the Perl 6 given/when construct.

use feature qw(switch);

You also get the switch feature whenever you declare that your code prefers to run under a version of Perl that is 5.10.1 or later. For example:

use v5.10.1;

The Perl 5 version 18.0 documentation says:

Under the “switch” feature, Perl gains the experimental keywords given, when, default, continue, and break. Starting from Perl 5.18, you can prefix the switch keywords with CORE:: to access a feature without including the use feature. In the following example, each feature is prefixed with the CORE:: label:

CORE::given ( some_variable) {
CORE::when( /abc/) { statements }

(The CORE namespace gives you access to the original built-in functions of Perl. For more on CORE, see http://perldoc.perl.org/CORE.html.)

The code in Example 7.33 can be rewritten as shown in Example 7.34.

7.5 What You Should Know

1. What are control structures?

2. What are blocks?

3. Are curly braces optional after the if or else constructs?

4. What is the purpose of the else block?

5. What construct allows for multiple choices?

6. How does a while loop differ from a do/while? From an until?

7. How do you break out of a loop before you reach the end of the enclosing block?

8. What is a redo statement? How does it differ from the next statement?

9. Why would you use next rather than redo to control a loop?

10. What is an infinite loop?

11. How does a foreach loop work?

12. Does Perl support a switch statement? What is the switch feature?

13. What is CORE::?

14. What is a continue block used for?

7.6 What’s Next?

In the next chapter, you will learn about pattern matching with regular expressions, one of the best and most important features of the language. You will learn about expression modifiers and how to find patterns in text strings. If you are familiar with the UNIX grep or the vi editor, you will see how Perl enhances and simplifies the power of pattern matching with its matching and substitution operators and large selection of regular expression metacharacters.

Exercise 7: What Are Your Conditions?

1. Physicists tell us that the lowest possible temperature is absolute zero. Absolute zero is -459.69 degrees Fahrenheit.

a. Accept inputs from the user: a beginning temperature, an ending temperature, and an increment value (all Fahrenheit).

b. Check for bad input: a temperature less than absolute zero and an ending temperature less than a beginning temperature. The program will send a message to STDERR if either condition is detected.

c. Print a header showing: Fahrenheit Celcius. Print all the values from the beginning to the ending temperatures. Use a looping mechanism. The conversion formula is C = (F - 32) / 1.8.

2. Ask the user for a list of grades, separated by whitespace. The grades will be stored in a string called $input.

a. Split the string $input and create an array.

b. Use the foreach loop to get the total sum of all the grades.

c. Print the average.

3. Write a script that will print 10 random number cards from a deck.

a. The script will build a deck of 52 cards by using nested foreach loops.

b. The outer loop will iterate through a list consisting of cards for each suit: clubs, diamonds, hearts, spades. The inner loop will iterate through a list for each type of card within the suit: ace, 2 through 10, jack, queen, and king. A card of each suit will be assigned to an array.

c. The rand() function will be used to get a random card from the pack. There should be no duplicates in the 10 cards selected from the deck. (Hint: the splice function is often used to remove the duplicate card.)

4. Remove the colors in @drop from the array @colors; that is, remove pink and brown from the array @colors.

@colors=qw(red green blue yellow pink purple brown);

@drop=qw(pink brown);

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.88.54