Lesson 4 -- Printer Friendly Version
INSTRUCTIONS:
IMPORTANT: This version of your lesson is for saving or printing only. All links and images have been disabled to decrease download time and help you avoid printer difficulties.
Chapter 1
Two of the most common activities you will perform as a perl programmer are pattern matching and decision-making.Pattern matching is the process of extracting a specific sequence of letters, numbers, and/or punctuation marks from a variable. Pattern matching is usually incorporated into a decision-making process in order to carry out activities like the following:
-verify that a user filled in all required fields on a form;
-prevent obscene or insulting messages from being added to a bulletin board;
-make sure that a user has entered the proper username and password;
-stop hackers from using your CGI program to issue dangerous operating-system level commands to your server;
-ensure that credit card numbers, zip codes, phone numbers, social security numbers, e-mail addresses and other types of critical variable information have been entered by users in the proper format;
-guarantee that quantities, weights, prices and other numbers supplied by users and used by your program are neither too large or too small or do not contain fractions or other forbidden values.
In a nutshell, then, pattern matching and decision-making operations help ensure the data you collect from users of your program is valid and useful.
Let's begin by looking at decision-making:
Decision-Making
In Perl, we use the 'if' statement to help our programs make decisions. An 'if' statement has three components:1. The word 'if';
2. A pattern-matching test, which must be surrounded by (parentheses); and
3. One or more instructions, which must be surrounded by {curly brackets}. Each instruction must end with a semicolon.
An 'if' statement, then, would look something like this:
if (test goes here) {instructions go here;}If you'd like, you can type the 'if' statement on two or more lines, like this:
if (test goes here) {instructions go here;}Some programmers like to separate the curly brackets from the instructions a bit. The programmer then indents the instructions inside the curly brackets so the curly brackets are easier to see. A Perl program will not run unless each open curly bracket is paired with a closed curly bracket.Separating the curly brackets from the instructions makes it easier for the programmer to see whether each set of instructions in the 'if' statement is surrounded by a pair of curly brackets.
if (test goes here) { instructions go here; }If you decide to write your 'if' statements in this way, I would strongly encourage you to use spaces or TABs to indent the instructions inside the curly brackets. The indentation makes it easier to see the curly brackets, so you'll be more likely to spot any missing brackets in your program when you perform error-checking. As you type your script, the indentation will serve as a constant reminder that the instructions are supposed to be surrounded by curly brackets. When you close the curly bracket, you can stop indenting your code.In an 'if' statement, the instructions contained within the curly brackets will only be processed if the test turns out to be true.
If you need to perform a series of tests, you could write out a series of 'if' statements, like this:
if (test 1 goes here) { instructions if test 1 is true go here; } if (test 2 goes here) { instructions if test 2 is true go here; }Unfortunately, 'if' statements require more time for your server to handle than any other command. The more 'if' statements you add to your program, the longer it will take to run. From the standpoint of efficiency and speed, it is in your best interests to limit the number of 'if' statements in your Perl script.
else
One of the best ways to limit the number of 'if' statements is to incorporate 'else' statements into your decision-making structure.When you use multiple 'if' statements, each and every one of them must be processed. In the example above, test 2 must always be performed. The outcome of test 1 doesn't matter in the least.
What's cool about 'else' statements is that they are only processed if the 'if' statement turned out to be false. If the 'if' statement turned out to be true, the server can skip the 'else' statement altogether. Each time the server is able to skip the 'else' statement, your program will run faster.
To add an 'else' statement to your decision-making structure, you just add the word 'else,' followed by a series of instructions. Each of these instructions should end with a semicolon, and the whole lot of them should be surrounded by a pair of curly brackets. Here's how it might look:
if (test goes here) { instructions if test is true go here; } else { instructions if test is false go here; }Again, the 'else' statement will only be processed if the 'if' statement turns out to be false. If the 'if' statement is true, your server gets to leap to the end of the entire decision-making structure displayed above. This structure results in an increase in efficiency and speed over a structure that uses two 'if' statements in a row.
elsif
What if the situation you need to test isn't a simple yes/no, true/false condition? If that's the case, the 'if/else' decision-making structure described above won't help, will it?Of course not. That's why Perl includes the 'elsif' statement. Elsif statements are only processed when the preceding 'if' statement is false. If the 'if' statement turns out to be true, the server gets to save processing time by skipping the intervening 'elsif' statements.
if (test 1 goes here) { instructions if test1 is true go here; } elsif (test 2 goes here) { instructions if test 1 is false; and test2 is true go here; } elsif (test 3 goes here) { instructions if test 1 is false; and test 2 is false; and test 3 is true go here; } else { instructions if test 1 is false; and test 2 is false; and test 3 is false go here; }In the example above, the server would skip both 'elsif' statements and the 'else' statement if test 1 turns out to be true. Allowing out server to skip lines in our script is equivalent to our taking a shortcut on a long journey. Either scenario could result in a significant time savings.If we had used four different 'if' statements instead of the 'if-elsif-else' structure displayed above, each and every one of those four 'if' statements would have had to be processed every single time your program is run. Under those circumstances, the outcome of any one single 'if' statement would have absolutely no impact on the next. That doesn't sound like an efficient design, does it?
The point I am trying to make is this: when writing Perl scripts, please try to avoid creating decision-making structures that rely on numerous 'if' statements unless you have no alternative. If you can, try to use 'elsif' and 'else' statements to build the most efficient decision-making structures possible.
unless
There may be times when you want to perform a test that is processed only if a condition is false. An 'if' statement won't do this, of course. Under these circumstances, you'll want to use an 'unless statement. Think of an 'unless' statement as if it were the opposite of an 'if' statement. Use 'unless' when 'if' can't do the job.You could use 'unless' to write instructions that would only be processed if a file did not exist, or if a variable did not contain a certain value, for example:
unless (test goes here) { instructions if test is false go here; }You cannot team up an 'elsif' with an 'unless' statement. Although 'else' might work with 'unless' under some circumstances, I wouldn't recommend creating that sort of structure. It is considered standard practice to only pair 'else' and 'elsif' structure for two or more tests in a row. For clarity's sake, only use 'unless' statements all by themselves and only when you cannot perform the test with an 'if' statement.OK--enough with the theory! All of this will become abundantly clear once we have some concrete, real-world examples. To learn all about the types of tests you can perform with these decision-making structures, please proceed to the next chapter.
Chapter 2
Pattern Matching
What kind of tests can be performed inside of an 'if', 'elsif', or 'unless' statement? Well, there are basically two types of tests:-numeric tests, which are tests involving numbers;
-string tests, which are tests involving words, phrases, sentences, and the like.
Both types of tests rely on 'operators,' special characters that are used to indicate which type of test is being performed. A list of these operators follows, along with examples of their proper use:
Numeric Test Operators
== (equal to)This operator can be used to determine whether a variable and a number (or a pair of variables) are identical to one another. Note the use of two equal signs. Remember, as you learned in the last lesson, we use one equal sign to assign a value to a variable.
From now on, you must always remember to use two equal signs when comparing a variable to a value. This is a very common cause of program errors, so please don't forget this simple rule: one if assigning, two if comparing. If you violate this rule and try to perform a test with one '=' sign instead of two, your test will not work and your program may crash or return invalid results.
Example:
if ($qty==0) { print "<p>You forgot to select a quantity!</p>"; } else { print "<p>Thank you for your order</p>"; }
!= (not equal to)This is just the opposite of the == operator.
Example:
if ($qty!=0) { print "<p>Thank you for your order</p>"; } else { print "<p>You forgot to select a quantity!</p>"; }
> (greater than)Use this operator to determine whether or not a variable is larger than a number or another variable.
Example:
if ($qty>0) { print "<p>Thank you for your order</p>"; } else { print "<p>You must order one or more items!</p>"; }
< (less than)Use this operator to determine whether or not a variable is smaller than a number or another variable.
Example:
if ($qty<1) { print "<p>You must order one or more items!</p>"; } else { print "<p>Thank you for your order</p>"; }
>= (greater than or equal to)Use this operator to determine whether or not a variable is larger than or identical to a number or another variable.
Example:
if ($qty>=1) { print "<p>Thank you for your order</p>"; } else { print "<p>You must order at least one item.</p>"; }
<= (less than or equal to)Use this operator to determine whether or not a variable is smaller than or identical to a number or another variable.
Example:
if ($qty<=0) { print "<p>You must order at least one item.</p>"; } else { print "<p>Thank you for your order</p>"; }
Chapter 3
In the preceding chapter, you learned about numeric test operators, which can be used on numbers. Now, let's look at string test operators. These operators can be used on words, phrases, and alphanumeric values (such as account numbers, phone numbers, and any other values containing a mixture of letters, numbers, spaces, and punctuation marks).
eq (equal to)This operator can be used to determine whether a variable and a string (or a pair of variables) are identical to one another. Please understand that the two values must be completely identical in both spelling and case for this test to evaluate as true. No differences in spelling or case will be tolerated.
For example, let's suppose your web site has a form that requests a password from your user. Your user types the password and submits the form to you. Your program then stores whatever your user typed and submitted in a variable named $password. (By the way, you'll learn how to do this in lessons 7 through 12 and beyond.) The following test validates the password:
if ($password eq "HawkEye") { print "<p>Welcome to our web site!</p>"; } else { print "<p>Get lost--your password was incorrect.</p>"; }In the example above, if your user types HawkEye, they'll see the welcome message. If they type open, sesame or 5555 or password or hawkeye or Hawkeye, or HawkEyes or anything other than HawkEye, they'll be told to Get lost!What if you didn't want the test to be case-sensitive? Well, if your hosting service has Perl 5 installed on their server, you're in luck. Perl 5 comes with a function called lc() that will temporarily convert any string value to lower case. (If you haven't already guessed, the 'lc' in this function's name stands for lower-case.)
You can use the lc() function to convert the variable you're testing to lower case so you can perform a case-insensitive comparison.
The function is easy to use. All you have to do is slip the name of the variable in between the two parentheses that follow the letters 'lc', like this:
lc($password)Then, just use this lower case version of the variable in your 'if' statement. Don't forget to change the other value in the comparison to lower case, as well, or you won't get a match! Here's an example:
if (lc($city) eq "chicago") { print "<p>My kind of town, Chicago is!</p>"; } else { print "<p>You ought to visit Chicago!</p>"; }In this example, if your user types Chicago or chicago or CHICAGO or even cHiCaGo, they'll see a fragment of a Sinatra lyric. This is because whatever they type is first converted to lower case and then compared with 'chicago'. The test is not case-sensitive.Now, if your user submitted Oklahoma City or Boise or Toronto or anything that doesn't convert to chicago when the uppercase letters are swapped for lowercase letters, he or she will be invited to the windy city instead.
ne (not equal to)This is just the opposite of the eq operator.
Example:
if ($password ne "HawkEye") { print "<p>Get lost--your password was incorrect.</p>"; } else { print "<p>Welcome to our web site!</p>"; }
gt (greater than)Use this operator to determine whether or not a variable would be sorted alphanumerically after a string or another variable.
Note: When values are sorted alphanumerically, punctuation marks are sorted first, then digits between 0 and 9, and then the letters from A to Z. Therefore, an exclamation point would be sorted before the number 35, which would be sorted before the word "Ann."
Example:
if ($ZipCode gt "90000-0000") { print "<p>You live in the Western US</p>"; } else { print "<p>You don't live in the Western US</p>"; }Note: Because zip codes, phone numbers, social security numbers, dates, credit card numbers and the like contain non-numeric values such as slashes and dashes, they are considered strings. Numeric values can contain only periods and the digits 0 through 9.
lt (less than)Use this operator to determine whether or not a variable would be sorted alphanumerically before a string or another variable.
Example:
if ($ZipCode lt "90000-0000") { print "<p>You don't live in the Western US</p>"; } else { print "<p>You live in the Western US</p>"; }
ge (greater than or equal to)Use this operator to determine whether or not a variable is larger than or identical to a string or another variable.
Example:
if ($choice ge "A") { print "<p>Thank you for your input!</p>"; } else { print "<p>Please type a letter from A to Z.</p>"; }
le (less than or equal to) Use this operator to determine whether or not a variable is smaller than or identical to a string or another variable.Example:
if ($time le "08:59") { print "<p>We are only open from 9 am until 12 am.</p>"; } else { print "<p>We're here to serve you!</p>"; }
&& (and)This operator can be used to perform more complex numeric or string tests. The && operator is used when your test should contain two or more conditions. When && is used, both tests must evaluate true. If only one test turns out to be false, the 'else' instructions will be processed.
Example:
if ($ZipCode ge "90000-0000"&& $ZipCode le "91999-9999") { print "<p>You live near Los Angeles.</p>"; } else { print "<p>You don't live near Los Angeles.</p>"; }
|| (or)This operator can also be used to perform complex numeric or string tests. When || is used, two or more tests are evaluated. If one or more of the tests turns out to be true, the 'else' instructions will NOT be processed.
Note: The '|' character (also known as a "pipe") can be found on the same key as the backslash on most keyboards. You must hold down the SHIFT key while typing a backslash in order to generate the pipe character.
Example:
if ($gender eq "M" || $gender eq "F") { print "<p>Thanks for sharing your gender with us!</p>"; } else { print "<p>Please respond with either M or F.</p>"; }But what if your user typed an 'm' or an 'f' instead of an 'M' or an 'F'? It doesn't seem fair to penalize the user with an error message simply because he or she forgot to hold down the SHIFT key, does it? You could have made this test case-insensitive by applying the lc() function to each instance of the variable named $gender. If you convert the variable to lower case, you must also remember to convert the comparison strings ('M' and 'F', in this example) to lower case:
if (lc($gender) eq "m" || lc($gender) eq "f") { print "<p>Thanks for sharing your gender with us!</p>"; } else { print "<p>Please respond with either M or F.</p>"; }
But what if the user responded with 'male' or 'female' instead of 'm' or 'f'? We could make those acceptable values with this modification of our decision making structure:
if (lc($gender) eq "m" || lc($gender) eq "male") { print "<p>Thank you, sir!</p>"; } elsif (lc($gender) eq "f" || lc($gender) eq "female") { print "<p>Thank you, ma'am!</p>"; } else { print "<p>Please respond with either M or F.</p>"; }
=~/string/ (contains)One problem with using 'eq' to perform comparisons is that it is a little to strict. If your user doesn't type exactly what you're looking for, any test involving 'eq' will evaluate to false. This means that if the user types 'reddish' when you're looking for 'red', or if they type 'Microsoft Windows' when you were just looking for 'Windows', you won't get a match.
Fortunately, there is a way to search for a specific string inside of a variable. Below, please find an example:
Note: The '~' character (also known as a tilde) can be found in the extreme upper left corner of most keyboards. Like the pipe, this character must also be SHIFTed.
Example:
if ($answer =~/Picasso/) { print "<p>Correct! The artist was indeed Picasso</p>"; } else { print "<p>Sorry. The correct answer was Picasso</p>"; }In the example above, responses of "Picasso" or "Pablo Picasso" or "that Picasso guy" or "Picasso, Pablo" would all evaluate true. But if your user were to respond with "picasso&" or "PICASSO&", the test would evaluat false. This is because, as written, the test is case-sensitive.
There are two ways to resolve the situation. If you're running Perl 5, you could use the lc() function to convert $answer to lower case. Then, you just compare the answer to "picasso" (the lower case version of "Picasso"), like this:
if (lc($answer) =~/picasso/) { print "<p>Correct! The artist was indeed Picasso</p>"; } else { print "<p>Sorry. The correct answer was Picasso</p>"; }
Another way to resolve the problem would be to slip an 'i' just after the last slash on the end of the search string, like this: Example:
if ($answer =~/Picasso/i) { print "<p>Correct! The artist was indeed Picasso</p>"; } else { print "<p>Sorry. The correct answer was Picasso</p>"; }The 'i' causes the comparison to be completely insensitive to the case of either the variable or the string you're searching for.In the example above, responses of "Picasso" or "picasso" or "PICASSO" or "pIcAsSo" or "Pablo Picasso" or "that picasso guy" or "Picasso, Pablo" would all evaluate true.
!=~/string/i does not contain...case-insensitive)This is simply the opposite of the example directly above.
Example:
if ($answer !=~/picasso/i) { print "<p>Sorry. The correct answer was Picasso</p>"; } else { print "<p>Correct! The artist was indeed Picasso</p>"; }
Chapter 4
Now, here's an example of a complete Perl program containing an 'if' statement:
#!/usr/local/bin/perl #Line above gives path to Perl interpreter #Initialize variable $quantity=25; #If this were a real program, our user would #be supplying us with the quantity using an #HTML form. We'll learn all about forms and #form processing in our next lessons. #Warn browser that HTML is coming print "Content-type: text/html\n\n"; #Produce beginning of HTML page print <<"PrintTag"; <html><head> <title>Order Confirmation</title> </head><body> PrintTag #Verify $quantity is greater than 0 if ($quantity > 0) { print "<p>Thanks for your order.</p>"; } else { print "<p>Please order something!</p>"; } #End of HTML page print "</body></html>"; #End of programThat's it for this lesson. In our next lesson, you'll learn how to upload your CGI programs to a server, set the file permissions, and test and debug the program. If you haven't taken my 'Advanced Web Pages' course (or even if you have), you'll also get a complete tutorial on building HTML forms with lesson 5.Once you know how to create HTML forms, we'll spend the rest of this course building interactive scripts that can respond to your clients' every desire. Please rest up--it's gonna be a big month!
Chapter 5
-Quiz 4-When you feel you have a grasp on all of the concepts taught within this lesson, I would like you to take a short, multiple choice quiz. To get to the quiz, click on 'Quizzes' on the menu bar. When the form comes up, input your last name, e-mail address, and password, and make sure you have 'Quiz 4' selected. Good luck!
-Assignment C-
Create a Perl program with the following three numeric variables:
$FeetPerMile $Feet $MilesAssign a value of 5280 to the variable named $FeetPerMile. Assign an initial value of 0 to the variable named $Feet. Assign any value you want to the variable named $Miles.Have your program perform a calculation that will determine the value of $Feet by multiplying $Miles by $FeetPerMile.
Then, have your program produce a web page that produces one of three possible messages.
If the value of $Feet is less than or equal to 0, have the page display the message:
Enter more miles, please.If the value of $Feet is greater than or equal to 10560, have the page display the message:
Better take the bus!If the value of $Feet is simultaneously greater than 0 and less than 10560, have the page display the message:
You're within walking distance.This assignment is to be completed on your own. A possible solution appears below (try not to peek until you've written your program), so there is no need to send me anything. Please post a question in the discussion area if you have any problems.
Possible Assignment Solution
This is just one solution. Your program may differ slightly.
#!/usr/bin/perl $Miles=1.5; $FeetPerMile=5280; $Feet=0; print "Content-type: text/html\n\n"; $Feet=$Miles*$FeetPerMile; print <<"PrintTag"; <html><head> <title>Results of Calculation</title> </head><body bgcolor="white" text="black"> PrintTag if ($Feet <= 0) { print "<p>Enter more miles, please.</p>"; } elsif ($Feet >= 10560) { print "<p>Better take the bus!</p>"; } else { print "<p>You're within walking distance.</p>"; } print "</body></html>"; #End of program
IMPORTANT: This version of your lesson is for saving or printing only. All links and images have been disabled to decrease download time and help you avoid printer difficulties. Do NOT attempt to click any of the links on this page.
Copyright 1999 by ed2go.com. All rights reserved.
No reproduction or redistribution without written permission.