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:
while
until
for
foreach
Each loop is followed by a block of statements enclosed in curly braces.
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 (non-null); while(1) is always true and loops forever. An expression is false if it evaluates to zero (null); while(0) is false and never loops.
Often, the while statement is used to loop through a file. (See "Reading from the Filehandle" on page 288.)
Code View: (The Script) #!/usr/bin/perl 1 $count=1; # Initialize variables $beers=10; $remain=$beers; $where="on the shelf"; 2 while ($count <= $beers) { if ($remain == 1){print "$remain bottle of beer $where ." ;} else {print "$remain bottles of beer $where $where .";} print " Take one down and pass it all around.\n"; print "Now ", $beers - $count , " bottles of beer $where!\n"; 3 $count++; 4 $remain--; 5 if ($count > 10){print "Party's over. \n";} } print "\n"; (Output) 10 bottles on the shelf on the shelf. Take one down and pass it all around. Now 9 bottles of beer on the shelf! 9 bottles on the shelf on the shelf. Take one down and pass it all around. Now 8 bottles of beer on the shelf! 8 bottles on the shelf on the shelf. Take one down and pass it all around. Now 7 bottles of beer on the shelf! 7 bottles on the shelf on the shelf. Take one down and pass it all around. Now 6 bottles of beer on the shelf! 6 bottles on the shelf on the shelf. Take one down and pass it all around. Now 5 bottles of beer on the shelf! 5 bottles on the shelf on the shelf. Take one down and pass it all around. Now 4 bottles of beer on the shelf! 4 bottles on the shelf on the shelf. Take one down and pass it all around. Now 3 bottles of beer on the shelf! 3 bottles on the shelf on the shelf. Take one down and pass it all around. Now 2 bottles of beer on the shelf! 2 bottles on the shelf on the shelf. Take one down and pass it all around. Now 1 bottle of beer on the shelf! 1 bottle of beer on the shelf on the shelf. Take one down and pass it all around. Now 0 bottles of beer on the shelf! Party's over. Explanation
|
The until statement executes the block as long as the control expression after the until is false, or zero. When the expression evaluates to true (nonzero), the loop exits.
Formatuntil (Expression) {Block} Example 7.8.
|
(The Script) #!/usr/bin/perl 1 print "Are you o.k.? "; 2 chomp($answer=<STDIN>); 3 until ($answer eq "yes"){ 4 sleep(1); 5 print "Are you o.k. yet? "; 6 chomp($answer=<STDIN>); 7 } 8 print "Glad to hear it!\n"; (Output) 1 Are you o.k.? n 1 Are you o.k. yet? nope 1 Are you o.k. yet? yup 1 Are you o.k. yet? yes 8 Glad to hear it! Explanation
|
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.
Formatdo {Block} while (Expression); do {Block} until (Expression); Example 7.10.
|
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. Any or all of the expressions can be omitted, but the two semicolons cannot.[1] 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.
[1] The infinite loop can be written as: for(;;)
Formatfor (Expression1;Expression2;Expression3) {Block} The above format is equivalent to the following while statement: Expression1; while (Expression2) {Block; Expression3}; Example 7.11.
|
Code View: (The Script) #!/usr/bin/perl # Initialization, test, and increment, decrement of # counters is done in one step. 1 for ($count=1, $beers=10, $remain=$beers, $where="on the shelf"; $count <= $beers; $count++, $remain--) { 2 if ($remain == 1){ print "$remain bottle of beer $where $where " ; } else { print "$remain bottles of beer $where $where."; } print " Take one down and pass it all around.\n"; print "Now ", $beers - $count , " bottles of beer $where!\n"; 3 if ($count == 10 ){print "Party's over.\n";} } (Output) 10 bottles of beer on the shelf on the shelf. Take one down and pass it all around. Now 9 bottles of beer on the shelf! 9 bottles of beer on the shelf on the shelf. Take one down and pass it all around. Now 8 bottles of beer on the shelf! 8 bottles of beer on the shelf on the shelf. Take one down and pass it all around. Now 7 bottles of beer on the shelf! < continues > 2 bottles of beer on the shelf on the shelf. Take one down and pass it all around. Now 1 bottle of beer on the shelf! 1 bottle of beer on the shelf on the shelf. Take one down and pass it all around. Now 0 bottles of beer on the shelf! Party's over. Explanation
|
If you are familiar with C shell programming, the Perl foreach loop is similar in appearance and behavior to the C shell foreach loop, but appearances can be deceiving and there are some obvious differences between the two constructs. So, read on.
The foreach loop iterates over each element in the parenthesized list, an array, assigning each element of the array 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.
Formatforeach VARIABLE (ARRAY) {BLOCK} Example 7.13.
|
Code View: (The Script) 1 foreach $hour (1 .. 24){ # The range operator is used here 2 if ($hour > 0 && $hour < 12) {print "Good-morning.\n";} 3 elsif ($hour == 12) {print "Happy Lunch.\n";} 4 elsif ($hour > 12 && $hour < 17) {print "Good afternoon.\n";} 5 else {print "Good-night.\n";} } (Output) 2 Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. Good-morning. 3 Happy Lunch. 4 Good afternoon. Good afternoon. Good afternoon. Good afternoon. 5 Good-night. Good-night. Good-night. Good-night. Good-night. Good-night. Good-night. Good-night. Explanation
|
Code View: (The Script) #!/usr/bin/perl 1 $str="hello"; 2 @numbers = (1, 3, 5, 7, 9); 3 print "The scalar \$str is initially $str.\n"; 4 print "The array \@numbers is initially @numbers.\n"; 5 foreach $str (@numbers ){ 6 $str+=5; 7 print "$str\n"; 8 } 9 print "Out of the loop--\$str is $str.\n"; 10 print "Out of the loop--The array \@numbers is now @numbers.\n"; (Output) 3 The scalar $str is initially hello. 4 The array @numbers is initially 1 3 5 7 9. 7 6 8 10 12 14 9 Out of the loop--$str is hello. 10 Out of the loop--The array @numbers is now 6 8 10 12 14. Explanation
|
(The Script) #!/usr/bin/perl 1 @colors=(red, green, blue, brown); 2 foreach (@colors) { 3 print "$_ "; 4 $_="YUCKY"; } 5 print "\n@colors\n"; (Output) 3 red green blue brown 5 YUCKY YUCKY YUCKY YUCKY Explanation
|
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 are optional but can be used to control the flow of a loop. 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.
FormatLABEL: while (Expression){Block} LABEL: while (Expression) {Block} continue{Block} LABEL: for (Expression; Expression; Expression) {BLOCK} LABEL: foreach Variable (Array){Block} LABEL: {Block} continue {Block} To control the flow of loops, the following simple statements may be used within the block: next next LABEL last last LABEL redo redo LABEL goto LABEL |
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, next can be used (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, last can be used 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.
A block is like a loop that executes once. A block can be labeled.
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 Script) #!//usr/bin/perl # Program that uses a label without a loop and the redo statement 1 ATTEMPT: { 2 print "Are you a great person? "; chomp($answer = <STDIN>); 3 unless ($answer eq "yes"){redo ATTEMPT ;} } (Output) 2 Are you a great person? Nope 2 Are you a great person? Sometimes 2 Are you a great person? yes Explanation |
Explanation
|
Code View: (The Script) 1 ATTEMPT:{ 2 print "What is the course number? "; chomp($number = <STDIN>); print "What is the course name? "; chomp($course = <STDIN>); 3 $department{$number} = $course; print "\nReady to quit? "; chomp($answer = <STDIN>); $answer=lc($answer); # Convert to lowercase 4 if ($answer eq "yes" or $answer eq "y") {last;} 5 redo ATTEMPT; } 6 print "Program continues here.\n"; (Output) 2 What is the course number? 101 What is the course name? CIS342 3 Ready to quit? n 2 What is the course number? 201 What is the course name? BIO211 3 Ready to quit? n 2 What is the course number? 301 What is the course name? ENG120 3 Ready to quit? yes 6 Program continues here. Explanation
|
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. Loops can be nested 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.
Explanation
|
(The Script) 1 for ($rows=5; $rows>=1; $rows--){ 2 for ($columns=1; $columns<=$rows; $columns++){ 3 printf "*"; 4 } 5 print "\n"; 6 } (Output) 3 ***** **** *** ** * Explanation
|
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.
Code View: (The Script) # This script prints the average salary of employees # earning over $50,000 annually # There are 5 employees. If the salary falls below $50,000 # it is not included in the tally 1 EMPLOYEE: for ($emp=1,$number=0; $emp <= 5; $emp++){ 2 do { print "What is the monthly rate for employee #$emp? "; print "(Type q to quit) "; 3 chomp($monthly=<STDIN>); 4 last EMPLOYEE if $monthly eq 'q'; 5 next EMPLOYEE if (($year=$monthly * 12.00) <= 50000); 6 $number++; 7 $total_sal += $year; next EMPLOYEE; 8 } while($monthly ne 'q'); } 9 unless($number == 0){ 10 $average = $total_sal/$number; 11 print "There were $number employees who earned over \$50,000 annually.\n"; printf "Their average annual salary is \$%.2f.\n", $average; } else{ print "None of the employees made over \$50,000\n"; } (Output) 2 What is the monthly rate for employee #1? (Type q to quit) 4000 2 What is the monthly rate for employee #2? (Type q to quit) 5500 2 What is the monthly rate for employee #3? (Type q to quit) 6000 2 What is the monthly rate for employee #4? (Type q to quit) 3400 2 What is the monthly rate for employee #5? (Type q to quit) 4500 11 There were 3 employees who earned over $50,000 annually. Their average annual salary is $64000.00. Explanation
|
The continue block with a while loop preserves the correct semantics as a for loop, even when the next statement is used.
Code View: (The Script) #! /usr/bin/perl# # Example using the continue block 1 for ($i=1; $i<=10; $i++) { # $i is incremented only once 2 if ($i==5){ 3 print "\$i == $i\n"; 4 next; } 5 print "$i "; } print "\n"; print '=' x 35; print "\n"; # --------------------------------------------------------- 6 $i=1; 7 while ($i <= 10){ 8 if ($i==5){ print "\$i == $i\n"; 9 $i++; # $i must be incremented here or an # infinite loop will start 10 next; } 11 print "$i "; 12 $i++; # $i is incremented again } print "\n"; print '=' x 35; print "\n"; # ------------------------------------------------------- # The continue block allows the while loop to act like a for loop $i=1; 13 while ($i <= 10) { 14 if ($i == 5) { 15 print "\$i == $i\n"; 16 next; } 17 print "$i "; 18 }continue {$i++;} # $i is incremented only once (Output) 1 2 3 4 $i == 5 6 7 8 9 10 =================================== 1 2 3 4 $i == 5 6 7 8 9 10 =================================== 1 2 3 4 $i == 5 6 7 8 9 10 Explanation
|
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. The following example demonstrates the way a switch statement is designed in the C language, PHP, etc.
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 Perl 5. (It will be in Perl 6.) 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 loop control statements, such as last, next, and redo, can be used within this block, you can create a "phoney" switch statement by adding a do block, which will execute a sequence of commands within the block. See Example 7.24.
Code View: (The Script) #! /usr/bin/perl 1 $hour=0; 2 while($hour < 24) { 3 SWITCH: { # SWITCH is just a user-defined label 4 $hour < 12 && do { print "Good-morning!\n"; 5 last SWITCH;}; 6 $hour == 12 && do { print "Lunch!\n"; last SWITCH;}; 7 $hour > 12 && $hour <= 17 && do { print "Siesta time!\n"; last SWITCH;}; 8 $hour > 17 && do { print "Good night.\n"; last SWITCH;}; } # End of block labeled SWITCH 9 $hour++; } # End of loop block (Output) Good-morning! Good-morning! Good-morning! <Output continues> Good-morning! Good-morning! Good-morning! Lunch! Siesta time! Siesta time! Siesta time! Siesta time! Siesta time! Good night. Good night. Good night. Good night. Good night. Explanation
|
If you still want a switch statement, the Switch.pm module can be found at: http://search.cpan.org/~rgarcia/Switch-2.13/Switch.pm. See Example 7.25.
(The Script) 1 use Switch; # Loads a Perl module 2 print "What is your favorite color? "; chomp($color=<STDIN>); 3 switch("$color"){ 4 case "red" { print "Red hot mama!\n"; } case "blue" { print "I got a feeling called the blues.\n"; } case "green" { print "How green my valley\n";} case "yellow" { print "In my yellow submarine";} 5 else { print "$color is not in our list.\n";} } 6 print "Execution continues here....\n"; (Output) 2 What is your favorite color? blue I got a feeling called the blues. 6 Execution continues here.... -------------------------------------- 2 What is your favorite color? pink pink is not in our list. 6 Execution continues here.... Explanation
|