64 exit; } Notice that in each if statement we execute the exit function since, if the condition is true, there is no reason to check any of the following conditions.. An indefinite l
Trang 1#!/usr/bin/perl
# walking.pl
use warnings;
use strict;
print "What's the weather like outside? ";
chomp(my $weather = <STDIN>);
print "How hot is it, in degrees? ";
chomp(my $temperature = <STDIN>);
print "And how many emails left to reply to? ";
chomp(my $work = <STDIN>);
if ($weather eq "snowing") {
print "It's snowing, let's go!\n";
} elsif ($weather eq "raining") {
print "No way, sorry, it's raining so I'm staying in.\n";
Trang 263
Let’s say it is 201
degrees, we’ve got 27 e-mails to reply to, and it’s cloudy out there:
$ perl walking.pl
What's the weather like outside? cloudy
How hot is it, in degrees? 20
And how many emails left to reply to? 27
Well, why not?
$
Looks like we can fit a walk in after all
The point of this rather silly little program is that once it has gathered the information it needs, it
runs through a series of tests, each of which could cause it to finish First, we check to see if it’s snowing:
if ($weather eq "snowing") {
print "It's snowing, let's go!\n";
If so, then we print our message and, this is the important part, do no more tests If not, we move on
to the next test:
} elsif ($weather eq "raining") {
print "No way, sorry, it's raining so I'm staying in.\n";
Again, if this is true, we stop testing; otherwise, we move on Finally, if none of the tests are true, we
get to the else:
} else {
print "Well, why not?\n";
}
Please remember that this is very different from what would happen if we used four separate if
statements The tests overlap, so it is possible for more than one condition to be true at once For
example, if it was snowing and we had over 30 emails to reply to, we’d get two conflicting answers elsif
tests should be read as “Well, how about if ?”
Now let’s update the program we saw earlier, guessnum1.pl, to use if/elsif/else The decision we made in the first version was implemented with three if statements:
Trang 364
exit;
}
Notice that in each if statement we execute the exit() function since, if the condition is true, there
is no reason to check any of the following conditions Instead of using the exit() function in each of the
if blocks, this would be better written with an if/elsif/else, as shown in guessnum2.pl:
print "Guess my number!\n";
print "Enter your guess: ";
my $guess = <STDIN>;
if ($target == $guess) {
print "That's it! You guessed correctly!\n";
} elsif ($guess > $target) {
print "Your number is more than my number\n";
} elsif ($guess < $target) {
print "Your number is less than my number\n";
}
The unless Statement
There’s another way of saying if (not $a) As always in Perl, there’s more than one way to do it.2
Trang 465
Expression Modifiers
When we talk in English, it’s quite normal to say
• If this is not true, then this happens, or
• Unless this is true, this happens
And it’s also quite natural to reverse the two phrases
• This happens if this is not true, or
• This happens unless this is true
In Perl-speak, we can take this if statement:
if ($number == 0) {
die "can't divide by 0";
}
and rewrite it as follows:
die "can't divide by 0" if $number == 0;
Notice how the syntax here is slightly different, it’s action if condition There is no need for
parentheses around the condition, and there are no curly braces around the action Indeed, the
indentation isn’t part of the syntax, so we can even put the whole statement on one line Only a single
statement will be covered by the condition This form of the if statement is called an expression
you may find it more natural to write this:
die "\$name has a false value" unless $name;
Using Short-Circuited Evaluation
There is yet another way to do something if a condition is true By using the fact that Perl stops
processing a logical operator when it knows the answer, we can create a sort of unless conditional:
$name or die "\$name has a false value";
How does this work? Well, it relies on the fact that Perl uses short-circuited, or lazy, evaluation to
give a logical operator its value If we have the statement X or Y, then if X is true, it doesn’t matter what
Y is, so Perl doesn’t look at it If X isn’t true, Perl has to look at Y to see whether or not that’s true So if
Trang 566
$name has a true value, then the die() function will not be executed Instead, Perl will do nothing and
continue on to execute the next statement
This form of conditional is most often used when checking that something we did succeeded or returned a true value We will see it often when we’re handling files
To create a positive if conditional this way, use and instead of or For example, to add one to a
counter if a test is successful, you can say
$success and $counter++;
As you’ll recall, and statements require both substatements to be true So, if $success is not true, Perl won’t bother evaluating $counter++ and upping its value by 1 If $success is true, then it would
or the heat death of the universe occurs, whichever comes first
There’s also a difference between definite loops and indefinite loops In a definite loop, you know in
advance how many times the block will be repeated An indefinite loop will check a condition in each iteration to determine whether it should loop again
There’s also a difference between an indefinite loop that checks before the iteration, and one that checks afterward The latter will always go through at least one iteration, in order to get to the check, whereas the former checks first and so may not go through any iterations at all
Perl supports ways of expressing all of these types of loops First, let’s examine the while loop
The while Loop
Let’s start with indefinite loops These check a condition, then do an action, then go back and check the
condition again We’ll look first at the while loop As you might guess from the name, this type of loop keeps doing something while a condition is true The syntax of while is much like the syntax of if:
while ( condition ) { action }
Once again, those curly braces are required Here’s a very simple while loop:
Trang 6Let’s see a flow chart for this program While there’s still a value greater than 0 in the $counter
variable, we do these two statements:
print "Counting down: $countdown\n";
$countdown ;
Perl goes through the loop a first time when $countdown is 5; the condition is met, so a message is
printed and $countdown gets decreased to 4 Then, as the flow chart illustrates, back we go to the top of the loop We test again: $countdown is still more than 0, so off we go again Eventually, $countdown is 1, we print our message, $countdown is decreased, and now it’s 0 This time around, the test fails, and we exit
the loop
while (<STDIN>)
Recall that we talked about using <STDIN> to read from standard input (normally the keyboard) This
statement reads the next line of standard input, up to and including the newline character:
$line_in = <STDIN>;
Trang 768
We can put this assignment within a while loop that will read from standard input until end of file (in Unix a ^D, or the Ctrl and D keys pressed at the same time; in Windows a ^Z<enter>) This loop reads a line at a time into $line_in and then prints that line:
while ($line_in = <STDIN>) {
print $line_in;
}
This behavior, reading from standard input until end of file, is so common that if <STDIN> is by itself within the while loop parentheses (and only within the while loop parentheses), then the line of
standard input is magically assigned to the special variable $_ This loop reads each line into $_, and then
the line is printed:
Let’s look at an example of using this magic variable $_ This program will loop through standard
input one line at a time until end of file, and for each line it will print a message followed by the line entered:
Trang 869
■ Note In Unix, end of file is ^D (Control-D) In Windows, end of file is ^Z<ret> (yes, you have to type the return key) You will have to adjust the example above if you are working in Windows
The $_ variable is very useful—it is the default argument for many different functions, such as the
chomp() function The statement
chomp $_;
could have been written as
chomp;
Many Perl programmers find it convenient and readable to write a loop like this one:
while ($line = <STDIN>) {
Whether or not you write code to take advantage of the magic nature of $_ is up to you, but we
suggest you practice with it enough to be able to read code that others have written using $_
Infinite Loops
The obvious but important point is that what we’re testing gets changed inside the loop If our condition
is always going to give a true result, we have an infinite loop Let’s just remove the second of those two statements:
Trang 970
$countdown never changes It’s always going to be 5, and 5 is, we hope, always going to be more than
0 So this program will keep printing its message until you interrupt it by holding down Ctrl and D Hopefully, you can see why you need to ensure that what you do in your loop affects the condition Should we actually want an infinite loop, there’s a fairly standard way to do it Just put a true value—
typically 1—as the condition:
while (1) {
print "Bored yet?\n";
}
The converse, of course, is to say while (0) in the loop’s declaration, but nothing will ever happen
because this condition is tested before any of the commands in the loop are executed A bit silly really
Trang 1071
■ Note The negation of > is <=, not < Yes, we have made the same mistake many times.…
The for Loop
Perl has a for loop, similar to the one found in C, C++, and Java Its syntax is
for (init_expression; test_expression; step_expression) {
action
}
The init_expr is done first and once Then the test_expr is tested to be true or false If true, the
action is executed, then the step_expr is executed Then the test_expr is tested to be true or false, and so
on
The most common use of a for loop is as an alternative way of writing a while loop that might
resemble this one:
This can be written in a for loop as
for ($i = 1; $i <= 5; $i++) {
# do something important
}
The foreach Loop
Perl has another loop called the foreach loop It is used to loop through lists and arrays We will talk
about arrays in the next chapter, but since we have seen examples of a list, we can look at the foreach
loop processing a list of numbers:
Trang 1172
The foreach loop executes the body of the loop (the print() function in this example) for each
number in the list $number is called the loop control variable, and it takes on the values in the list, one at
a time Recall that (1 10) is shorthand for (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) The following code
produces this result:
$ perl foreach.pl
the number is: 1
the number is: 2
the number is: 3
the number is: 4
the number is: 5
the number is: 6
the number is: 7
the number is: 8
the number is: 9
the number is: 10
This accomplishes two things: first, it satisfies use strict; since $number gets declared with my(), and second,
it lexically scopes $number to the body of the foreach (it is not available outside the looping construct)
A note about the keywords for and foreach: they are synonyms for each other In other words, we
We will talk more about foreach in the next chapter when we discuss the array data type
do while and do until
When we were categorizing our lists, we divided indefinite loops into those that execute at least once
and those that may execute zero times The while loop we’ve seen so far tests the condition first and so,
Trang 1273
if the condition isn’t true the first time around, the “body” of the loop never gets executed There are two other ways to write our loop to ensure that the body is always executed at least once:
do { action } while ( condition );
do { action } until ( condition );
Now we do the test after the block This is equivalent to moving the diamond in our flow chart from the top to the bottom
the value of $i: 1
the value of $i: 2
the value of $i: 3
the value of $i: 4
the value of $i: 5
starting do until
the value of $i: 1
the value of $i: 2
the value of $i: 3
the value of $i: 4
the value of $i: 5
$
The importance of the do while and do until loops is that the body of the loop is always executed
at least once
Trang 13statement until condition;
Therefore, this loop:
while (<STDIN>) {
print "You entered: $_";
}
can be written as
print "You entered: $_" while <STDIN>;
Loop Control Constructs
Perl provides constructs that let us control the flow of our loops They allow us to break out of a loop, go
to the next iteration of the loop, or reexecute the loop We’ll start with breaking out of a loop
Trang 14Note that last1.pl could have been written using an expression modifier It can be argued that this
code is a bit more readable:
print "All done!\n";
Going On to the Next
If you want to skip the rest of the processing of the body on the current iteration, but don’t want to exit
the loop, you can use next to immediately go execute the next iteration of the loop by testing the
expression Here is an example of a program that reads input from the user, and if the line of input is not blank, the line is printed It the line is blank, the program immediately goes back to read the next line:
Trang 15Reexecuting the Loop
On rare occasions, you’ll want to go back to the top of the loop, but without testing the condition (in the
case of a for or while loop) or getting the next element in the list (as in a for or while loop) If you feel you need to do this, the keyword to use is redo, as illustrated in this example:
Trang 1778
the last statement within the innermost loop construct (while ($j <= 5)) will last out of the innermost looping construct only Therefore, each time $j reaches 3 within the inner loop, we last out of the inner loop and increment $i, then go back up to test the expression for the outer while loop This generates
the following output:
To make the last statement last out of the outer looping construct, we must label the outer looping
construct with a loop label A loop label is a variable that the programmer creates (it is recommended
that you use all uppercase names) followed by a colon, preceding the looping construct This is
Trang 1879
goto
As a matter of fact, you can put a label before any statement whatsoever If you want to really mess
around with the structure of your programs, you can use goto LABEL to jump anywhere in your program
It is highly recommended that you don’t use this construct Really, we mean it Don’t use it Caveat
emptor
We’re telling you about it for the simple reason that if you see it in anyone else’s Perl, you can laugh
heartily at them goto with a label is to be avoided like the plague
Why? Because not only does it turn the clock back 30 years (the structured programming movement started with the publication of a paper called “Go To Statement Considered Harmful”), but it tends to
make your programs incredibly hard to follow The flow of control can shoot off in any direction at any time, into any part of the file, maybe into a different file You can even find yourself jumping into the
middle of loops, which really doesn’t bear thinking about Don’t use it unless you really, really, really
understand why you shouldn’t And even then, don’t use it Larry Wall has never used goto with a label
in Perl, and he created Perl
Summary
Before this chapter, our programs plodded along in a straight line, one statement followed by another We’ve now seen how we can react to different circumstances in our programs, which is the start of
flexible and powerful programming We can test whether something is true or false using if and unless,
and take appropriate action
We’ve also examined how to test multiple related conditions using elsif We can repeat areas of a program, in several different ways, using while, until, for, and foreach Finally, we’ve examined some ways to alter the flow of Perl’s execution through these loops We can break out of a loop with last, skip
to the next element with next, and start processing the current element again with redo
Exercises
1 Modify the number-guessing program guessnum2.pl so that it loops until the
correct answer is entered
2 Write a program that prints the squares of the numbers between 1 and 10
3 Write a program to print all the numbers between 1 and 50 that are evenly
divisible by 5 Loop by 1, not by 5!
Trang 20■ ■ ■
81
Lists and Arrays
In Chapter 2 we introduced the idea of a scalar, which is a single value—a number or string Having the ability to work with numbers and strings, and having scalar variables into which we can store numbers and strings is nice—this allows us to write programs to manipulate data However, because they can
contain only a single value, scalars are somewhat limited
There are times we want to group information together or express correspondences between
information Just like the ingredients in a recipe or the pieces in a jigsaw, some things belong together in
a natural sequence: for example, individual lines in a file, or the names of players in a volleyball
tournament In Perl, we represent these relationships in lists—series of scalars Lists can be stored in
another type of variable called an array, and we call each piece of data in the list an element
In this chapter, we’ll see how to create and work with lists We’ll also take another look at the
foreach loop, which enables us to step through lists and arrays
Lists
We’re all familiar with lists from everyday life Think about a grocery store shopping list: what properties does it have? First of all, it’s a single entity, one piece of paper Second, it’s made up of a number of
values In the case of a shopping list, you might want to say that these values are actually strings—
“potato chips”, “Guinness”, “cheese”, and so on Finally, it’s also ordered, which means that there’s a
first item and a last item
Lists in Perl aren’t actually much different; they’re counted as a single unit, though they’re made up
of a number of values In Perl, these values are scalars, rather than purely strings, and they’re stored in the order they appear in the list
We’ll specify lists in our program code as literals, just like we did with strings and numbers And
we’ll be able to perform certain operations on them Let’s begin by looking at a few simple lists and how
to create them
Trang 2182
Simple Lists
The simplest shopping list is one that contains nothing at all1
Similarly, the simplest list in Perl has no
elements in it, and it is called the empty list Here’s what it looks like:
As you can see, we have created two lists, one containing a number, and one containing a string—so
far so good Remember the print() function? It treats its arguments as lists, and the magic about functions like print() that treat their arguments as lists is that you can omit the parentheses Saying print "cheese" is just the same as saying print("cheese") So now we know that what we give to print()
is really a list, and we’re allowed to leave out the parentheses if we wish
From this, we should be able to work out how to put multiple values into a list When we said
zeroth element is "Hello ", the first is "world", and the second is "\n" Now, let’s do that again with
numbers instead of strings:
Trang 2283
As before, Perl doesn’t automatically put spaces between list elements for us when it prints them
out, it just prints them as it sees them Similarly, it doesn’t put a newline on the end for us2 There’s
nothing special about lists from that point of view; if we want to add spaces and newlines, we need to
put them into the list ourselves
More Complex Lists
We can also mix strings, numbers, and variables in our lists Let’s see an example of a list with several
different types of data Although this isn’t very different from what we were doing with print() in
Chapter 2, this example reinforces the idea that lists can contain any scalar literals and scalar variables
So, type this in, and save it as mixedlist.pl:
Notice that the print() function prints a list of six elements, including literal strings, literal
numbers, and a scalar variable for good measure
Trang 23One last thing to note is that Perl automatically flattens lists That is, if you try putting a list inside
another list, the internal list loses its identity In effect, Perl removes all the parentheses apart from the outermost pair There’s no difference at all between any of these three lists:
(3, 8, 5, 15)
((3, 8), (5, 15))
(3, (8, 5), 15)
Similarly, Perl sees each of these lists exactly the same as the others:
('one', 'two', 'three', 'four')
(('one', 'two', 'three', 'four'))
('one', ('two', 'three'), 'four')
(('one','two'), ('three', 'four'))
So we can say that in Perl all lists (and all arrays) are one-dimensional
Creating Lists Easily with qw//
Perl provides a useful operator that lets us easily create lists of one-word strings The operator is qw//,
which stands for quote words It is related to the other “q” operators we saw in Chapter 2: q// and qq//
The qw// operator takes all the items within the slashes that are separated by whitespace characters and
creates a single-quoted list of them For instance, this code: