Chapter 2: Perl Variables
Before you can proceed much further with CGI programming, you'll need some
understanding of Perl variables and data types. A variable is a place to store a
value, so you can refer to it or manipulate it throughout your program. Perl has
three types of variables: scalars, arrays, and hashes.
A D V E R T I S E M E N T
Scalars
A scalar variable stores a single (scalar) value. Perl scalar names are
prefixed with a dollar sign ($), so for example, $x, $y, $z, $username, and $url
are all examples of scalar variable names. Here's how variables are set:
In this example $foo, $name, and $pi are scalars. You do not have to declare
a variable before using it, but its considered good programming style to do so.
There are several different ways to declare variables, but the most common way
is with the my function:
my simultaneously declares the variables and limits their
scope (the area of code that can see these variables) to the enclosing code
block. (We'll talk more about scope later.) You can declare a variable without
giving it a value:
You can also declare several variables with the same my
statement:
You can omit the parentheses if you are declaring a single variable, however
a list of variables must be enclosed in parentheses.
A scalar can hold data of any type, be it a string, a number, or whatnot. You
can also use scalars in double-quoted strings:
Now if you print $blee, you will get "The magic number is 23." Perl
interpolates the variables in the string, replacing the variable name with the
value of that variable.
Let's try it out in a CGI program. Start a new program called scalar.cgi:
Program 2-1: scalar.cgi Print Scalar Variables Program
#!/usr/bin/perl -wT
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use strict;
my $email = "fnord\@cgi101.com";
my $url = "http://www.cgi101.com";
print header;
print start_html("Scalars");
print <<EndHTML;
<h2>Hello</h2>
<p>
My e-mail address is $email, and my web url is
<a href="$url">$url</a>.
</p>
EndHTML
print end_html;
You may change the $email and $url variables to show your own e-mail address*
and website URL. Save the program, chmod 755 scalar.cgi, and test it in your
browser.
You'll notice a few new things in this program. First, there's use
strict . This is a standard Perl module that requires you to declare all
variables. You don't have to use the strict module, but it's considered good
programming style, so it's good to get in the habit of using it.
You'll also notice the variable declarations:
Notice that the @-sign in the e-mail address is escaped with (preceded by) a
backslash. This is because the @-sign means something special to Perl � just as
the dollar sign indicates a scalar variable, the @-sign indicates an array, so
if you want to actually use special characters like @, $, and % inside a
double-quoted string, you have to precede them with a backslash (\).
A better way to do this would be to use a single-quoted string for the e-mail
address:
Single-quoted strings are not interpolated the way double-quoted strings are,
so you can freely use the special characters $, @ and % in them. However this
also means you can't use a single-quoted string to print out a variable, because
will print the actual string "$fnord" . . . not the value stored in the
variable named $fnord.
Arrays
An array stores an ordered list of values. While a scalar variable can only
store one value, an array can store many. Perl array names are prefixed with an
@-sign. Here is an example:
Each individual item (or element) of an array may be referred to by its index
number. Array indices start with 0, so to access the first element of the array
@colors, you use $colors[0]. Notice that when you're referring to a single
element of an array, you prefix the name with $ instead of @. The $-sign again
indicates that it's a single (scalar) value; the @-sign means you're talking
about the entire array.
If you want to loop through an array, printing out all of the values, you
could print each element one at a time:
A much easier way to do this is to use a foreach loop:
For each iteration of the foreach loop, $i is set to an element of the
@colors array. In this example, $i is "red" the first time through the loop. The
braces {} define where the loop begins and ends, so for any code appearing
between the braces, $i is set to the current loop iterator.
Notice we've used my again here to declare the variables. In the foreach
loop, my $i declares the loop iterator ($i) and also limits its scope to the
foreach loop itself. After the loop completes, $i no longer exists.
We'll cover loops more in Chapter 5.
Getting Data Into And Out Of Arrays
An array is an ordered list of elements. You can think of it like a group of
people standing in line waiting to buy tickets. Before the line forms, the array
is empty:
Then Howard walks up. He's the first person in line. To add him to the
@people array, use the push function:
Now Sara, Ken, and Josh get in line. Again they are added to the array using
the push function. You can push a list of values onto the array:
This pushes the list containing "Sara", "Ken" and "Josh" onto the end of the
@people array, so that @people now looks like this: ("Howard", "Sara", "Ken",
"Josh")
Now the ticket office opens, and Howard buys his ticket and leaves the line.
To remove the first item from the array, use the shift function:
This sets $who to "Howard", and also removes "Howard" from the @people array,
so @people now looks like this: ("Sara", "Ken", "Josh")
Suppose Josh gets paged, and has to leave. To remove the last item from the
array, use the pop function:
This sets $who to "Josh", and @people is now ("Sara", "Ken")
Both shift and pop change the array itself, by
removing an element from the array.
Finding the Length of Arrays
If you want to find out how many elements are in a given array, you can use
the scalar function:
my @people = ("Howard", "Sara", "Ken", "Josh");
my $linelen = scalar(@people);
print "There are $linelen people in line.\n";
This prints "There are 4 people in line." Of course, there's always more than
one way to do things in Perl, and that's true here � the scalar function is not
actually needed. All you have to do is evaluate the array in a scalar context.
You can do this by assigning it to a scalar variable:
This sets $linelen to 4.
What if you want to print the name of the last person in line? Remember that
Perl array indices start with 0, so the index of the last element in the array
is actually length-1:
Perl also has a handy shortcut for finding the index of the last element of
an array, the $# shortcut:
$#arrayname is equivalent to scalar(@arrayname)-1 .
This is often used in foreach loops where you loop through an array by its index
number:
my @colors = ("cyan", "magenta", "yellow", "black");
foreach my $i (0..$#colors) {
print "color $i is $colors[$i]\n";
}
This will print out "color 0 is cyan, color 1 is magenta", etc.
The $#arrayname syntax is one example where an #-sign does not indicate a
comment.
Array Slices
You can retrieve part of an array by specifying the range of indices to
retrieve:
This example sets @slice to ("magenta", "yellow").
Finding An Item In An Array
If you want to find out if a particular element exists in an array, you can
use the grep function:
/pattern/ is a regular expression for the pattern you're looking
for. It can be a plain string, such as /Box kite/ , or a complex
regular expression pattern.
/pattern/ will match partial strings inside each array element.
To match the entire array element, use /^pattern$/ , which anchors
the pattern match to the beginning (^ ) and end ($ ) of
the string. We'll look more at regular expressions in Chapter 13.
grep returns a list of the elements that matched the pattern.
Sorting Arrays
You can do an alphabetical (ASCII) sort on an array of strings using the
sort function:
@colors2 becomes the @colors array in alphabetically sorted order ("black",
"cyan", "magenta", "yellow" ). Note that the sort function, unlike push and pop,
does not change the original array. If you want to save the sorted array, you
have to assign it to a variable. If you want to save it back to the original
array variable, you'd do:
You can invert the order of the array with the reverse function:
@colors is now ("black", "yellow", "magenta", "cyan").
To do a reverse sort, use both functions:
@colors is now ("yellow", "magenta", "cyan", "black").
The sort function, by default, compares the ASCII values of the
array elements This means if you try to sort a list of numbers, you get "12"
before "2". You can do a true numeric sort like so:
my @numberlist = (8, 4, 3, 12, 7, 15, 5);
my @sortednumberlist = sort( {$a <=> $b;} @numberlist);
{ $a <=> $b; } is actually a small subroutine, embedded right in
your code, that gets called for each pair of items in the array. It compares the
first number ($a) to the second number ($b) and returns a number indicating
whether $a is greater than, equal to, or less than $b. This is done repeatedly
with all the numbers in the array until the array is completely sorted.
We'll talk more about custom sorting subroutines in Chapter 12.
Joining Array Elements Into A String
You can merge an array into a single string using the join
function:
my @colors = ("cyan", "magenta", "yellow", "black");
my $colorstring = join(", ",@colors);
This joins @colors into a single string variable ($colorstring), with each
element of the @colors array combined and separated by a comma and a space. In
this example $colorstring becomes "cyan, magenta, yellow, black".
You can use any string (including the empty string) as the separator. The
separator is the first argument to the join function:
The opposite of join is split , which splits a
string into a list of values. See Chapter 7 for more on split.
Array or List?
In general, any function or syntax that works for arrays will also work for a
list of values:
my $color = ("red", "green", "blue")[1];
# $color is "green"
my $colorstring = join(", ", ("red", "green", "blue"));
# $colorstring is now "red, green, blue"
my ($first, $second, $third) = sort("red", "green", "blue");
# $first is "blue", $second is "green", $third is "red"
Hashes
A hash is a special kind of array � an associative array, or paired list of
elements. Each pair consists of a string key and a data value.
Perl hash names are prefixed with a percent sign (%). Here's how they're
defined:
Hash Name key value
my %colors = ( "red", "#ff0000",
"green", "#00ff00",
"blue", "#0000ff",
"black", "#000000",
"white", "#ffffff" );
This particular example creates a hash named %colors which stores the RGB HEX
values for the named colors. The color names are the hash keys; the hex codes
are the hash values.
Remember that there's more than one way to do things in Perl, and here's the
other way to define the same hash:
Hash Name key value
my %colors = ( red => "#ff0000",
green => "#00ff00",
blue => "#0000ff",
black => "#000000",
white => "#ffffff" );
The => operator automatically quotes the left side of the argument, so
enclosing quotes around the key names are not needed.
To refer to the individual elements of the hash, you'll do:
Here, "red" is the key, and $colors{'red'} is the value associated with that
key. In this case, the value is "#ff0000".
You don't usually need the enclosing quotes around the value, either; $colors{red}
also works if the key name doesn't contain characters that are also Perl
operators (things like +, -, =, * and /).
To print out all the values in a hash, you can use a foreach loop:
This example uses the keys function, which returns a list of the
keys of the named hash. One drawback is that keys %hashname will
return the keys in unpredictable order � in this example, keys %colors
could return ("red", "blue", "green", "black", "white") or ("red", "white",
"green", "black", "blue") or any combination thereof. If you want to print out
the hash in exact order, you have to specify the keys in the foreach loop:
foreach my $color ("red","green","blue","black","white") {
print "$colors{$color}=$color\n";
}
Let's write a CGI program using the colors hash. Start a new file called
colors.cgi:
Program 2-2: colors.cgi - Print Hash Variables Program
#!/usr/bin/perl -wT
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
use strict;
# declare the colors hash:
my %colors = ( red => "#ff0000", green=> "#00ff00",
blue => "#0000ff", black => "#000000",
white => "#ffffff" );
# print the html headers
print header;
print start_html("Colors");
foreach my $color (keys %colors) {
print "<font color=\"$colors{$color}\">$color</font>\n";
}
print end_html;
Save it and chmod 755 colors.cgi, then test it in your web browser.
Notice we've had to add backslashes to escape the quotes in this
double-quoted string:
A better way to do this is to use Perl's qq operator:
qq creates a double-quoted string for you. And it's much easier
to read without all those backslashes in there.
Adding Items to a Hash
To add a new value to a hash, you simply do:
Using our colors example again, here's how to add a new value with the key
"purple":
If the named key already exists in the hash, then an assignment like this
overwrites the previous value associated with that key.
Determining Whether an Item Exists in a Hash
You can use the exists function to see if a particular key/value
pair exists in the hash:
This returns a true or false value. Here's an example of it in use:
This checks to see if the key "purple" is already in the hash; if not, it
adds it.
Deleting Items From a Hash
You can delete an individual key/value pair from a hash with the delete
function:
If you want to empty out the entire hash, do:
Values
We've already seen that the keys function returns a list of the
keys of a given hash. Similarly, the values function returns a list
of the hash values:
my %colors = (red => "#ff0000", green=> "#00ff00",
blue => "#0000ff", black => "#000000",
white => "#ffffff" );
my @keyslice = keys %colors;
# @keyslice now equals a randomly ordered list of
# the hash keys:
# ("red", "green", "blue", "black", "white")
my @valueslice = values %colors;
# @valueslice now equals a randomly ordered list of
# the hash values:
# ("ff0000", "#00ff00", "#0000ff", "#000000", "#ffffff")
As with keys , values returns the values in
unpredictable order.
Determining Whether a Hash is Empty
You can use the scalar function on hashes as well:
This returns true or false value � true if the hash contains any key/value
pairs. The value returned does not indicate how many pairs are in the hash,
however. If you want to find that number, use:
Here's an example:
my %colors = (red => "#ff0000", green=> "#00ff00",
blue => "#0000ff", black => "#000000",
white => "#ffffff" );
my $numcolors = scalar(keys(%colors));
print "There are $numcolors in this hash.\n";
This will print out "There are 5 colors in this hash."
|