77

Chapter 6:

Stacking The Blocks

Since we cannot be universal
and know all that is to be known of everything,
we ought to know a little about everything.

- Pascal, Pensées (1670), 37, tr. W. F. Trotter

The previous chapter covered the basic building blocks of most program-
ming languages: literals and variables, expressions and statements, opera-
tors, commands, and control flow. By putting these basic constructs together
in various ways, you can build programs of arbitrary size and complexity.

Input And Output (I/O)

Most programs act upon data(information). They take data from some-
where (input), process it in some manner, and produce a report or perhaps
new data that has been transformed in some way (output).

Input can be provided in several ways. It can be hard-coded- stored inside
the program itself. It can be provided by interaction with the user (e.g.,
typing on a keyboard) or from a file which the program opens and reads.

Output can also be provided in several ways. The most common of these are
to write (e.g.,
print) to the screen or to open and write to a file.

So far, our examples have been very simple. They don't do very much and
they depend entirely on data that is hard-coded within the program (or
acquired mysteriously prior to the example). This isn't very flexible, how-
ever. Most programs operate on data acquired from the outside world.


IMAGE imgs/210.Stacking01.gif

We'll cover reading and writing files in the next chapter. For now, our pro-
grams will get their input directly from the keyboard and write their out-
put to the screen (specifically, to the
MacPerlwindow).1

We introduced the printcommand in the previous chapter. We will con-
tinue to use
printin these examples, both to prompt for input and to write
the results of our programs to the screen.

Input

If a program expects input to be typed on the keyboard, it should promptfor
input in some way; we will accomplish this by printing a request.

print('Please type something: ');

Note that we omitted the newline sequence, \n, from the printstatement.
This is a common way to put the prompt and the text the user types on the
same line.
2

Next, we need to tell Perl to expect some input from the keyboard, and to
store that input somewhere. Input that comes from the keyboard is said to
come from standard input. Note that standard input can be redirectedto
come from a file instead, but for now, we'll use the keyboard.

print('Please type something: ');
$input = <STDIN>;

Perl uses <STDIN>to read from the keyboard. This construct is known as the
line input operator, or, simply, the angle operator(for the angle brackets
which enclose it). The word within the angle brackets (e.g.,
STDIN) pro-
vides a handleto the location of the data.
3The variable $inputis set to
the input line.
4

IMAGE imgs/210.Stacking02.gif

1There are many other ways to handle input and output, such as mice, joysticks, bells
and lights, sound and video devices, etc. The most common input and output methods for
Perl scripts, however, involve typed user interaction and files.
2If your script uses the -lswitch, or sets the special variable, $\, a newline would be
printed even if not specified.
3We will cover filehandlesin the next chapter. For now, just remember that <STDIN>
retrieves a line of text entered .
4Of course, we could call this variable anything we want to. If we don't specifically
set a variable to the input line, Perl will set the special (magic) variable $_. $_is the
default pattern-searching and input space, and tends to crop up a lot. For now, we'll
be explicit about naming our variables, but remember that
$_is implicitly there.


IMAGE imgs/210.Stacking03.gif

Finally, we should do something with the data we have stored.

print('Please type something: ');
$input = <STDIN>;
print("You typed: $input\n");

If you have been using MacPerl to try this out, you may have noticed that
the program printed an extra blank line to the MacPerl output window.

IMAGE imgs/210.Stacking04.gif

This is because MacPerl reads everything you typed, including the return,
and stores the result in
$input. When Perl executes the next statement

print("you typed: $input\n");

the result is that two newlines are printed - one that is specified in the
code and one that is included in the
$inputvariable.

Unless you really want the extra newline, it could become annoying. The
chompfunction removes the newline from its argument, leaving the rest of
the string intact.
5

print('please type something: ');
$input = <STDIN>;
chomp($input);
print("you typed: $input\n");

More Commands?

While it can be useful to get some data from the keyboard and print it back,
this wouldn't be very interesting for long. Most programs do something with
the data they take in, such as performing calculations, comparing the data

IMAGE imgs/210.Stacking02.gif

5Actually, chompremoves the current line endingcharacter, if present. It returns
(evaluates to) a truth value indicating whether it found (and removed) anything.


IMAGE imgs/210.Stacking06.gif

with other data, and so forth. As we discussed in the previous chapter, you
tell Perl what to do with your data by issuing commands.

Perl has nearly 200 built-incommands (functions and named operators that
act like functions). These are available as an integral part of Perl; you don't
need to install them or do anything special to make them available. All
you need to do is tell Perl to run a command, specifing any necessary argu-
ments (data values for the command to act upon) in the proper order.

length()

For example, once you have your keyboard input, you could determine how
many characters were typed. The following examples assume that we are
adding code to the program we began writing above.

The lengthfunction determines the length of a character string and returns
it as a scalar value. We can capture that value in a variable, and store it
for future use or print it.

$len = length($input);
print("Your input is $len characters long.\n");

index()

Alternatively, you could determine whether there is a space(octal \040,
also known as a blank) in the input string, using the
indexfunction. The
indexfunction returns the position of the first occurrence of a given
substring(a portion of a larger string) in a given string.

# $position = index($str1, $str2, $offset);6

The indexfunction requires two arguments. The first ($str1) is the string
to search; the second (
$str2) is the desired substring. An optional third
argument (
$offset) tells Perl where in the string to begin the search. If
omitted, this starting offsetis taken to be
0.7

If the specified substring is not found when the string is searched, index
returns a value of -1. We'll add some error checkingcode to alert us if this
is the case.

IMAGE imgs/210.Stacking02.gif

6This line is commented to indicate that it is a syntax definition, not real code!
7Because Perl begins counting from 0, the index of the first character in a string (i.e.,
the index origin) is 0, rather than 1. As with so many things in Perl, the index origin
can be changed to something other than 0. Don't.


IMAGE imgs/210.Stacking08.gif

$position = index($input, ' ');
if ($position < 0) {
print("There are no blanks in your input.\n");
} else {
print("There is a blank at position $position.\n");
}

Note: If you are typing this example in, take care; there's a single
blank space between the single quotes in the statement

$position = index($input, ' ');

substr()

Now that we've found the first blank, we might want to print only the first
word of the input, that is, everything before the first blank in the string.
We know the position of the blank, and we can use the
substrfunction to
extract a substring from a string.

# $substr = substr($str1, $offset, $length);

Like index, substrrequires two arguments, but has an optional third
argument. The first two arguments specify the string to examine (
$str1)
and the offset (
$offset) from which to begin. The third ($length) speci-
fies the length of the substring to extract. If this is omitted, a substring will
be extracted from the position spefified by
offsetto the end of the string
(i.e., the maximum possible length).

if ($position < 0) {
$substr = $input;
} else {
$substr = substr($input, 0, $position);
}
print("The first word you typed was $substr.\n");

If there are no blanks in the input ($position < 0), we print the entire
input string. Otherwise, we extract a substring from position
0(the begin-
ning of the string) to the first blank. The length is easy to calculate in this
case, as it is equivalent to the value stored in
$position.8

IMAGE imgs/210.Stacking02.gif

8If you don't see why, take some paper and a pencil and try a few examples. Remember
to count characters in the string beginning with 0until you reach the first blank, then
go back and determine the length of the part before the blank. Hint: the lengthdoes not
start with
0unless there are no characters to count!


IMAGE imgs/210.Stacking10.gif

Note that it is acceptable to name a variable ($substr) with the same
name as a function! The
$prevents any confusion (on the part of Perl :-).

Putting it all together

If you have been following along with our example, your script should now
look something like this.

print('please type something: ');
$input = <STDIN>;
chomp($input);
print("you typed: $input\n");

$len = length($input);
print("Your input is $len characters long.\n");

$position = index($input, ' ');
if ($position < 0) {
print("There are no blanks in your input.\n");
} else {
print("There is a blank at position $position.\n");
}

if ($position < 0) {
$substr = $input;
} else {
$substr = substr($input, 0, $position);
}
print("The first word you typed was $substr.\n");

Pattern Matching

Perl excels at pattern matching, that is, comparing a string of data to a par-
ticular pattern of characters to see if it matches. A pattern, in this context,
describes any regular set or sequence of characters which might be present.

The pattern to be matched is described by an expression which can be used
anywhere a Perl expression can be used. When these expressions exploit
regularities (patterns) in the data, they are referred to as regular expres-
sions
.
9A pattern is specified by enclosing a pattern description between a
pair of delimitercharacters, usually /slashes/.

IMAGE imgs/210.Stacking02.gif

9There has been some discussion of whether Perl patterns are (truly) regular expres-
sions. Those who are interested in this discussion are referred to Tom Christiansen's
Perl Wizard's Quizin The Perl Journal, (vol. 2, no. 4), Winter 1997.


IMAGE imgs/210.Stacking12.gif

There are three variations on the basic pattern matching expression. Each
uses a different named operator, which is placed before the initial
delimiter character, and each has a slightly different format.
10

m//
s///
tr///

match
substitute
translate

m/pattern/
s/pattern/replacement/
tr/pattern/replacement/

In most cases, the goal is simply to search for (match) a particular pattern.
Occasionally, however, you may want to modify the data, based on the suc-
cess of the particular match. At these times, you'll want to use a substitu-
tion
or translationoperator.

Although the slash,/, is perhaps most common, any non-alphanumeric,
non-whitespace character can be used for the delimiters.
11And, because
matching is a very common operation, the
moperator is optional as long as
the delimiters used are slashes.If you decide to use some other character
(e.g.,
#), you must use mto tell Perl that this is a pattern matching
expression , as
m#pattern#. However, to explicitly indicate that a pattern
is to be matched, the
mmay be specified. If the operation is a substitution or
translation, the operator (
sor tr) is always required.12

Perl also has two binding operatorsfor use with pattern operations:

=~
!~

successful (matches)
unsuccessful (does not match)

Binding operators act somewhat differently from other operators we have
seen so far. Sometimes they act like comparison operators; at other times
they may seem more like asignment operators.

A binding operator bindsa scalar expression to a pattern operation (match,
substitution, or translation). The argument to the left of the binding opera-
tor consists of a scalar expression or string which will be searched (and pos-

IMAGE imgs/210.Stacking02.gif

10The translation operator, tr///, does not use regular expressions in its matches;
translation patterns are matched character for character. However, the troperator
looks and feels a lot like the
m//and s///operators, so itmakes sense to discuss it
along with the others.
11A ?is a special case, however. If you match a pattern using ?as the delimiter, ?abc?,
the pattern will be matched only once, finding only the first occurrence of the pattern.
No other delimiter choices have special meaning.
12You may see expressions of the form y/.../.../. The yis synonymous with tr.


IMAGE imgs/210.Stacking14.gif

sibly modifed). The argument to the right of the operator consists of the
pattern expression that performs the match, substitution, or translation.

Let's begin with a matching expression, as these are the most popular. Here
is another way to tell if there is a blank in your input string (if not what its
position is). We could add this code to the program we've been writing.

if ($input =~ / /) {
print("There is a blank in your input.\n");
} else {
print("There are no blanks in your input.\n");
}

The ifstatement compares the input string, stored in $input, to the pat-
tern described as
/ /(one blank space). The binding operator (=~) returns
success if the pattern matches the string (i.e., occurs anywhere in the
string). Note that we could also have written the
ifstatement as:

if ($input =~ m/ /) {

This pattern is quite simple: a single blank space, occurring anywhere in the
input line. Don't be fooled; patterns (and the corresponding expressions) can
be verycomplex and exceedingly powerful! So, hang on ...

Perl provides a number of tools for composing patterns, to make descriptions
easier to write.
13First, patterns generally contain literal characters,
which match themselves in the target string:

/ /
/hello/

Next, Perl provides a set of escape sequenceswhich may be used as a form of
shorthand in describing certain common types of characters or patterns.
Many of the escape sequences which can be used in
printstatements are
available for use in regular expressions as well (e.g.,
\t,tab, \n, newline,
\f, formfeed, and \a, "alarm" or "bell"). Some, however, have different
meanings (
\bis a backspace in a print statement but matches a word
boundary in a regular expression).

Here is an abbreviated list, to get you started. See Chapter 19, Operators,
for a complete list.

IMAGE imgs/210.Stacking02.gif

13Some people would disagree that any of this gets easier. Perhaps we should say,
more flexible.


IMAGE imgs/210.Stacking16.gif

\tmatch a tab character
\0nmatch an octal number n14
\dmatch any digit [0-9]
\Dmatch any nondigit
\wmatch any "word" character (letter, digit, or underscore)
\smatch any whitespace character (e.g., tab, space, newline)
\bmatch at a word boundary

Finally, Perl provides metacharacterswhich do not match themselves, but
which modify the nature of a pattern. For example, metacharacters may be
used to group parts of a pattern, to anchora pattern to the beginning or end
of a string, or to specify a certain number of repetitions.
15The backslash
character used in the escape sequences above is itself a metacharacter.

\"escape" character
[]describe a character class16
()parenthesize for grouping
*repeat the previous match 0 or more times
+repeat the previous match 1 or more times
?repeat the previous match 0 or 1 times
^anchor a pattern to the beginning of the line
$anchor a pattern to the end of the line
.match any (single) character
|alternation (choice of alternative matches)

Several of these metacharacters can also be combined to produce variations
in meaning (e.g., a character class, repeated one or more times).

Matching

We'll define a few patterns that you might use in the program we've been
constructing, to let you see how pattern matching works in context. Feel free

IMAGE imgs/210.Stacking02.gif

14A backslashed two- or three-digit octal number matches the character with that
octal(ASCII) value. For example, \015 matches the carriage returncharacter, ^M.
15If you ever wish to match one of these metacharacters literally, you must escapeit
by preceding it with a backslash. This removes the special meaning from the character.
16A character classis a set of characters, where the pattern may match any member of
the set. For example, the regular expression class [0123456789]describes the set of
digits from
0through 9, inclusive. For series classes, a dash, -, may be used to represent
missing but assumed members (e.g.,
[0-9]also represents the same set of digits).


IMAGE imgs/210.Stacking18.gif

to experiment by substituting one of these for the / /expression we used in
the previous example, or by writing new
ifstatements (be sure to modify
the associated
printstatements appropriately!).

/[A-Z]/# any capital letter
/^[A-Z]/# string starts with a capital letter
/[aeiou]/# any vowel
/\d\d\d/# a sequence of three digits
/ ....../# a space, followed by any 6 characters
/\./# a literal period
/\.$/# a period at the end of a string
/[1-3]+/# one or more instances of 1, 2, or 3
/Tue|Thu/# either Tue or Thu

Try entering the following strings as input to your program. Which patterns
will match which strings?

hello!
I cooked 12 eggs.
This is a sentence.
454 Maple Street
Thursday, Dec. 25 1997
Tom Thumb

What expressions could you write that would match the different patterns
found in the following string, extracted from a typical email message?

Date: Sun, 28 Dec 1997 20:37:03 -0500 (EST)

Which of the expressions you've written would be the hardest to fool (that
is, which is the least likely to match a string that is not a typical date
string?).
17Which expression would be the easiest to fool? What sort of
data could you create that would incorrectly match your patterns?

Substitution

The patterns we have used so far have only made use of Perl's matching
facility. However, text can also be replaced (substituted) if a match is suc-
cessful. A substitution expression looks very similar to a matching expres-
sion, except that it begins with an initial (required)
s. The substitution

IMAGE imgs/210.Stacking02.gif

17Hint: The "Tom Thumb" example above will "fool" a pattern designed to match days
of the week using /Tue|Thu/.


IMAGE imgs/210.Stacking20.gif

expression also describes the replacementtext which will be substituted for
the target text if a pattern match is successful.

The example below will substitute the string Decemberfor the string Dec.
if found. Try adding this code to the script we have been creating, then
enter one of the sample date strings shown previously under Matching.

$input =~ s/Dec\./December/;
print("The substituted string is: $input\n");

Used as shown, the substitution changes the value of a variable. If you
wanted to preserve that value, you could first set a new variable to have
the same value as the first, then change the new variable.

$newstring = $input;
$newstring =~ s/Dec\./December/;
print("The substituted string is: $newstring\n");
print("The original string is: $input\n");

Perl provides a convenient idiom (shortcut) for this type of operation.

($newstring = $input) =~ s/Dec\./December/;
print("The substituted string is: $newstring\n");

First, the lefthand side of the expression, ($newstring = $input)is
evaluated, setting
$newstringto the value of $input; next, $newstring
becomes the lefthand side of a new operation and the substitution takes
place. The final value of
$newstringis the substituted value.

The next example translates text files into Macintosh line-ending format.
Typically, Unix text files use a linefeed (octal
\012) at the ends of lines,
Macintosh text files use a carriage return (octal
\015), and DOS (and
Windows) text files use both. This pattern matches lines which end with
(no more than one) carriage return, followed by a linefeed, replacing
matching strings with a single carriage return.
18

($line = $input) =~ s/\015?\012/\015/;

Translation

Translation expressions are usually discussed along with pattern matching
and substitution, even though translation does not use regular expressions.

IMAGE imgs/210.Stacking02.gif

18You may have some difficulty entering any sample text for this substitution to work
on! Try this example again after we begin to work with files, in the next chapter.


IMAGE imgs/210.Stacking22.gif

Instead, translation searches a string, one character at a time, translating
(replacing) all occurrences of one set of characters into the corresponding
characters in another set.

The code below will translate all uppercase letters in the input string into
their lowercase counterparts.
19

($lower = $input) =~ tr/A-Z/a-z/;
print("The translated string is: $lower\n");

Breaking Data Apart

Earlier in this chapter we learned how to find the first word in an input
string by searching for the first blank space. But what if we wanted to find
the second word, or the last? And what if the words are separated by more
than one space or by another character such as a tab?

There is an easy way to break an input string into words or fields. split
breaks a character string into one or more substrings, based on a given sepa-
rating pattern (e.g., a tab, space, or other character). The
splitfunction
can be especially useful when working with data that has been exported
from a spreadsheet, a data base, or a calendar application, as these pro-
grams frequently have an option to export data as tab-separated text.

Unlike the functions we have used so far, splitreturns, not a scalar value,
but an array. Each element of the array contains one substring of the origi-
nal string.

We discussed arrays briefly in previous chapters. An array variable can
hold multiple values, in this example, split-up pieces of a string:

@pieces = split(/\t/, $input);
print("The first word is: $pieces[0]\n");
print("The last word is: $pieces[$#pieces]\n");

The splitfunction breaks the input string ($input), into pieces, or sub-
strings, based on a given pattern (e.g., a tab character,
/\t/). It returns an
array (
@pieces) containing those substrings.

Recall that Perl begins counting at 0, so the first element of the array is at
position (or offset, or index)
0and is expressed as $pieces[0]. Note that a

IMAGE imgs/210.Stacking02.gif

19Try adding this code to the script we have been creating, then enter some of the
sample input suggested previously under Matching.


IMAGE imgs/210.Stacking24.gif

single element of an array is itself a scalar value (single items are scalars);
use the
$prefix when referring to an array element.

Perl returns the index value of the last element of an array in the variable
$#arrayname, in this case, $#pieces. Because array indexes begin at 0,
the index of the last element will always be numerically
oneless than the
actual number of elements in an array.
20

$count = $#pieces + 1;
print("There are $count fields in your string.\n");

An Array Of Possibilities

Ordinary arrays are indexed by number; the first position is at 0and the
last is at $#arrayname. You could use a loop to walk through the array.
21

for ($i = $#pieces; $i >= 0; $i--) {
print("\$pieces[$i] contains: $pieces[$i]\n");
}

The loop above walks through the array in reverse order, from the last
element to the first. Of course, you could access an array in any order: first
element to last, last to first, or by some other method of your choosing. Here
is another style of loop that will print every item in an array, in order.

foreach $item (@pieces) {
print("$item\n");
}

You can fill an array in any of several ways. As we have seen, an array can
be returned by a function, such as
split. Or, you can fill the array yourself,
specifying the positions of each element (e.g., using a loop). Array elements
can be set to any values: numbers, strings, or the results of expressions. Note
that you do not have to fill every position in an array; the "empty" posi-
tions contain null(the empty string,
'', which coerces to 0) values.

IMAGE imgs/210.Stacking02.gif

20As an interesting side effect, if you use the array in a scalar context (i.e., treat the
variable as if it were a scalar value) it will return the length of the array (i.e., the
actual number of items in the array). Try:
$count = @pieces; print("There are $count fields."\n);
21TMTOWTDI: Alternatively, use the range operator, .., to create the loop:
foreach $i (0 .. $#pieces) {
print...


IMAGE imgs/210.Stacking26.gif

for ($i = 0; $i <= 15; $i += 5) {
$my_array[$i] = 1;
}
foreach $item (@my_array) {
print("$item");
}
print("\n");

Note:Perl does not require you to specify the size of an array before you
use it. An array will simply keep getting larger as you add more items
(until you run out of memory!). For efficiency's sake, however, you may
wish to "pre-allocate" large arrays by setting the value of the highest
position you expect to use:
$my_array[1000000] = '';

You can provide a listof values and Perl will fill your array for you, begin-
ning with position
0and continuing until there are no more values remain-
ing. This is a very common way to initializean array.

@colors = ('red', 'green', 'yellow', 'blue');
for ($i = 0; $i <= $#colors; $i++) {
print("position $i contains: $colors[$i]\n");
}

Perl provides several functions for working with arrays. push()and pop()
add and remove items from the "end" of an array (treating it as a stack).
shift()and unshift()also add and remove items, but at the "front" (in-
dex 0). By using these operators in concert, you can treat the array as a queue
or even a deque(double-ended queue).
splice(), the most general of these
functions, can add or remove items at arbitrary positions in an array.

Several interesting and useful arrays are predefined in MacPerl, including:

@ARGVthe array containing the command line arguments for a Perl
script (or list of files dropped onto a MacPerl droplet).

@INC

the array containing the list of places to look for Perl libraries;
this is set by the
Librariespreference.

Hashes

What if you wanted a more memorable way to index an array than by num-
bers? Alternatively, what if your array is sparse(containing many unused
positions)? For times when ordinary arrays are not what you need, Perl pro-
vides hashes (also known as associative arrays).


IMAGE imgs/210.Stacking27.gif

A hash also holds multiple values, but each value is indexed by a (possi-
bly) non-numeric key.
22You provide the keys as you fill the hash. The
items in a hash are unordered; that is, they are accessed by their keys but
there is no way of knowing what the internal structure of the hash is.
23You
might think that this lack of order would make hashes slow or difficult to
use. Actually, they are fast, easy to use, and quite powerful.

To distinguish a hash from an ordinary array, hash names begin with %.
When you refer to a single element of a hash, however, that element is a
scalar value and is prefixed with a
$; individual hash elements are dis-
tinguished from array elements by the use of braces,
{}, instead of brackets,
[], surrounding the key (index).

Let's get on to some examples.

Because the elements of a hash are unordered, Perl cannot provide the keys
for you as it could with the indexes of an ordinary array. You must provide
the keys as you fill the hash. A hash is initialized by providing a list of
key / value pairs. Every other item in the list (beginning with the first) is
a key; the alternating items are values.

%colors = ('ball', 'red', 'sky', 'blue');
print("The ball is $colors{'ball'}.\n");

It's not very easy to see the key / value pairs here, so we'll take advantage
of Perl's insensitivity to whitespace (Perl usually doesn't care where you
put extra blanks, tabs, and carriage returns) to reformat this statement as:

%colors = ('ball','red',
'sky','blue');

To make things even more readable, Perl provides the =>operator. It's just
a synonym for the comma, but it's easier to distinguish and more memora-
ble (if used correctly).
24

%colors = ('ball'=> 'red',
'sky'=> 'blue');

IMAGE imgs/210.Stacking02.gif

22If the key is numeric, it will be coerced to a string before it is used.
23In contrast, the elements of an ordinary array are ordered. The element at position
1is always between the elements at positions 0and 2.
24As a side effect, the =>operator forces the argument to its left to be interpreted as a
string. So you don't actually needto put in the quotes ... but we will anyway.


IMAGE imgs/210.Stacking29.gif

You might want to pronounce =>as "gets the value".

Hash items can be printed in the same way that ordinary array items are
printed (just remember to use braces,
{}, around the key!).25

print("The ball is $colors{'ball'}.\n");
print("The sky is $colors{'sky'}.\n");

This method of printing could get tedious, however. You may be wondering
if there is an equivalent to the loop commands we used with arrays, to print
each member of a hash. Because a hash is unordered, you cannot use a loop
with an incremented (or decremented) counter. However, you can use a
for
or foreachloop if you combine it with a function called keys.26

The keysfunction returns a list of all the keys in a specified hash. The
keys cannot be assumed to be returned in any particular order; that is, they
will most likely notbe returned in the order in which they were stored!

foreach $key (keys(%colors)) {
print("key: $key, color: $colors{$key}\n");
}

If a particular ordering is important, you can sort the retrieved keys.

foreach $key (sort(keys(%colors))) {
print("key: $key, color: $colors{$key}\n");
}

Perl has several functions for working with hashes: eachand valuesalso
return the elements of the hash (in different ways);
existsdetermines if a
particular key exists;
deleteremoves a specified key (and its value).

Many interesting and useful hashes are predefined in MacPerl, including

%ENV

contains information about your current environment; this is set
by the
Environmentpreference. In particular, $ENV{TMPDIR}is
the name of a folder where temporary files can be stored.

IMAGE imgs/210.Stacking02.gif

25The key need not be explicitly quoted, as the braces themselves provide quoting for
any single identifier (element) in a subscript. That is, $colors{ball}is usually
acceptible. Under certain circumstances, however, leaving out the quotes may generate
a warning if you use the
-wswitch, so be warned!
26The foreachkeyword is actually just a synonym for forso you can use whichever
you feel most comfortable using. In practice, the keywords are used as we show them;
that is,
foreachis most often used when iterating over an array or hash.


IMAGE imgs/210.Stacking31.gif

See Part IV, Reference, for more information on hash-related functions, pre-
defined hashes, etc.

Multiple Dimensions

It may sound like a term from a science fiction story, but Perl arrays can
have multiple dimensions. A multiply-dimensioned array is simply an
array of arrays - each element in the array is, itself, an array.
27Multiply-
dimensioned arrays can become very complex, and we'll only be giving you a
brief taste here. For a more complete and in-depth discussion, we refer you
to Programming Perland (perhaps) Advanced Perl Programming.

The following code creates a simple array of arrays which can be mapped
as a two-dimensional matrix. The first dimension is "vertical" (the rows);
the second is "horizontal" (the columns). What will the third
print
statement print?

@matrix = (
['yellow', 'purple', 'red','blue' ],
['pear','grape','apple', 'berry'],
['small','medium', 'large', 'huge' ],
);
print ("$matrix[0][0]\n");# prints yellow
print ("$matrix[1][1]\n");# prints grape
print ("$matrix[2][2] $matrix[0][1] $matrix[1][3]\n");

Context

Perl has two types of variables: ones which contain a singlevalue (scalars)
and ones which contain multiplevalues (arrays and hashes). Some func-
tions (e.g.,
length, index) return scalar values; others (e.g., split, keys)
return lists of values which can be assigned to an array.

Every operation in Perl is evaluated in a specific context. Assignment to an
array or a hash is said to be evaluated in a list context.
28List context is also
provided by assignment to a list of scalars. For example:

($a, $b, $c) = split (/ /, $line);

IMAGE imgs/210.Stacking02.gif

27