- Assignment Operators
- Increment and Decrement Operators
- String Concatenation and Repetition
- Operator Precedence and Associativity
- Using Patterns to Match Digits
- An Example: Simple Statistics
- Input and Output
- Another Example: Stocks
- A Note About Using Functions
- Going Deeper
- Summary
- Q&A
- Workshop
- Answers
An Example: Simple Statistics
Here's an example called stats.pl, which prompts you for numbers, one at a time. When you're done entering numbers, it gives you a count of the numbers, the sum, and the average. It's a rather silly kind of statistics script, but it'll demonstrate tests, variable assignment, and pattern matching for input verification (and we'll be building on this script later on). Here's an example of what it looks like when run (including what happened when I accidentally typed an r in the middle of entering the numbers):
% stats.pl Enter a number: 3 Enter a number: 9 Enter a number: 3 Enter a number: r Digits only, please. Enter a number: 7 Enter a number: 4 Enter a number: 7 Enter a number: 3 Enter a number: Total count of numbers: 7 Total sum of numbers: 36 Average: 5.14 %
Listing 3.1 shows the code behind the statistics script.
Listing 3.1 The stats.pl Script
1: #!/usr/local/bin/perl -w 2: 3: $input = ''; # temporary input 4: $count = 0; # count of numbers 5: $sum = 0; # sum of numbers 6: $avg = 0; # average 7: 8: while () { 9: print 'Enter a number: '; 10: chomp ($input = <STDIN>); 11: if ($input eq '') { last; } 12: 13: if ($input =~ /\D/) { 14: print "Digits only, please.\n"; 15: next; 16: } 17: 18: $count++; 19: $sum += $input; 20: } 21: 22: $avg = $sum / $count; 23: 24: print "\nTotal count of numbers: $count\n"; 25: print "Total sum of numbers: $sum\n"; 26: printf("Average (mean): %.2f\n", $avg);
This script has three main sections: an initialization section, a section for getting and storing the input, and a section for computing the average and printing out the results.
Here's the initialization section (with line numbers in place):
3: $input = ''; # temporary input 4: $count = 0; # count of numbers 5: $sum = 0; # sum of numbers 6: $avg = 0; # average
We're using four scalar variables here: one to store the input as it comes in, one to keep track of the count of numbers, one to hold the sum, and one to hold the average.
The next section is where you prompt for the data and store it:
8: while () { 9: print 'Enter a number: '; 10: chomp ($input = <STDIN>); 11: if ($input eq '') { last; } 12: 13: if ($input =~ /\D/) { 14: print "Digits only, please.\n"; 15: next; 16: } 17: 18: $count++; 19: $sum += $input; 20: }
This second part of the script uses a while loop and a couple if conditionals to read the input repeatedly until we get a blank line. And also to test the input to make sure that we didn't get anything that wasn't a number. I still haven't discussed how loops and conditionals are defined in Perl (and we won't get around to it until Day 6). So, I'm going to pause here and give you a very basic introduction so you will not be totally lost for the next few days.
A while loop says "while this thing is true, execute this stuff." With a while loop Perl executes a test, and if the test is true it executes everything inside the curly braces (here, everything in between lines 9 and 20). Then, it'll go back and try the test again, and if it's true again, it'll execute all that code again, and so on. The loop means it goes around and around and around until the test is false.
Usually, the test is contained inside the parentheses (line 8), and can be any of the tests you learned about yesterday. Here, there is no test, so this is an infinite loop; it never stops, at least not here. We'll find a way to break out of it from inside the loop.
An if conditional is simpler than a loop. An if conditional has a test, and if the test is true, Perl executes some code. If the test is false, sometimes Perl executes some other code (if the if conditional has a second part, called an else), and sometimes it just goes onto the next part of the script. So, for example, in the if conditional in line 11, the test is if the input is equal to the empty string ''. If the test is true, last is executed. The last keyword is used to immediately break out of a while loop and stop looping. If the test is false, Perl skips over line 11 altogether and continues onto line 13.
In the if conditional, lines 13 through 16, the test is a pattern match. Here we're testing the $input to see if it contains any nondigit characters. If it does, we execute the print statement in line 14, and then call next. The next keyword skips to the end of the while loop (in this case, skipping lines 18 and 19), and restarts the next loop at the top of the while again. Just as with line 11, if the test in line 13 was false, Perl skips over everything in line 13 to 16 and continues onto line 18 instead.
Now that you know about if and while, let's start at the top and figure out what this bit of code actually does. It's a while loop with no test, so it'll keep going forever until something breaks you out of it. Inside the body of the while, we use line 10 to grab the actual input (and I know you're still waiting to learn what chomp and <STDIN> do; it's coming up soon). Line 11, as I mentioned, tests for an empty string, and if we got one, breaks out of the loop. The empty string in the input will only occur if the user hit return without typing anything; that is the signal to the stats program that the end of input has been reached. Note the string test (ne) here; a number test would convert the empty string to 0, which is not what we want. 0 is valid input for the stats program.
When you get to line 13 we know we have something in $input, but we want to make sure that you have valid input, that is, numeric data. You're going to be performing arithmetic on this data in lines 18 and 19, and if you end up with nonnumeric data in the input, and warnings turned on, Perl is going to complain about that data. By verifying and rejecting invalid input you can make sure your scripts do not do unfriendly things like spew errors, or crash when your users are running them.
Lines 13 through 15 are the input validation test. If the input did contain nonnumeric data, we print an error and the loop restarts by prompting for new data.
By the time we get to line 18 we now know that we have data to be handled in $input and that data does not contain nonnumeric characters. Now we can add that new data to our current store of data. In lines 18 and 19 we increment the $count variable, and modify the $sum variable to add the new value that was input. With these two lines we can keep a running total of the count and the sum as each new bit of input comes along, but we'll wait until all the data has been entered to calculate the average.
And, finally, we finish up by calculating the average and printing the results:
22: $avg = $sum / $count; 23: 24: print "\nTotal count of numbers: $count\n"; 25: print "Total sum of numbers: $sum\n"; 26: printf("Average (mean): %.2f\n", $avg);
Line 22 is a straightforward calculation, and lines 24 through 26 print the count, the sum, and the average. Note the \n at the beginning of the first print statement; this will print an extra blank line before the summary. Remember that \n can appear anywhere in a string, not just at the end.
In the third summary line, you'll note we're using printf again to format the number output. This time, we used a printf format for a floating-point number that prints 2 decimal places of that value (%.2f). You get more information about printf in the next section.