Before we go any further, I figured I'd explain something.
It looks like I
am showing you all the boring stuff and nothing useful with it, and this
does appear to be the case so far, however there is a reason for that..
Unless you know about this stuff, you will not know how to do any of the
basic data manipulation required to do anything useful.. but hopefully, this
will be one of the last theory only primers, from here on in, I show you some
of the cool stuff, and then you will see why knowing about the basics is so
handy.. it might sound complicated now, but once you see it all in action,
it will all make sense and you'll wonder why you ever thought it was hard or
complicated.
(not that there aren't parts that are more difficult.) we have
nearly finished with the basics, so the fun useful stuff is nearly here.
If you've read this far, you might be wondering what possible uses loops might have.
I am going to try to give you some reasons right now.
You have already seen one example in the last primer where we used a foreach loop to go though an array
of data one item at a time looking for some specific text. That is but one example of their power.
A good example use of a loop would be to loop though a HTML file and strip out all the HTML tags and
remove them, or stip the headers from emails leaving just the message body, or sort though an array or
hash and extract or manipulate the data within. The uses are endless.
For example:
The default method of reading a text file in Perl is to use "open" and loop though the content
one line at a time using a while or foreach loop. Like so:
my $data_file = '/var/www/cgi-bin/mydata/data.txt'; open DATA, "$data_file" or die "can't open $data_file $!"; foreach my $line (<DATA>) { # do something to each line of the data here. # the variable $line will contain the each line of the file in turn. # For example, you might just want to print the line out. print $line; } close (DATA);
We can achieve the same thing with a while loop also:
while (<DATA>) { # The default variable $_ will contain the each line of the file in turn. # For example, you might just want to print the line out. print $_; }
The only limit of what you can do with loops is your imagination, and their abilities
will become more clear as you see examples of them in actual scripts.
Now I will show you each loop type in turn and explain how they are used.
"for" loops.
Assuming you read the earlier primers, you now know what a variable, an array
and a hash is.. you also have some idea about if/elsif/else/unless
statements, and we touched on for/foreach/while loops, I said I'd explain
the "for" example in the previous primer, so I'll do it now., Its not that
different to the ones I have already explained so this won't take long.
Here is the example I gave:
for (my $counter = 0; $counter <= 10000; $counter +=1;)
{
# Do stuff here!
}
This will look very familiar to anyone who is experienced in programming
with the C language. (and it won't look entirely unfamiliar to anyone
experienced with JavaScript and most other languages either.)
There are three expressions in this loops parentheses (the topmost brackets)
the first is an expression that sets the initial value of the loop variable.
(which in this case we used the variable $counter and set it to an initial
value of 0 (zero).
The second expression is the condition upon which we test if the loop should
continue.
(in this case, that the value of $counter is less then or equal to 10000.)
The third expression modifies the counter variable each time the loop
executes.
This one is interesting.. because $counter +=1; doesn't make much sense at
first glance.
Keep in mind that Perl programmers are generally lazy, they
want to achieve results with the least amount of effort possible, (which is
why they chose Perl in the first place.) so Perl is full of little shortcuts
that make for less typing.. this is just one of them.
$counter +=1; is the same as saying $counter = $counter + 1; (in other
words, we increment the value of $counter by adding 1 to it.) you could
actually put $counter = $counter + 1; in there instead of $counter +=1; and
it will work exactly the same.
So the for loop, read as English would be something like this:
The counter starts at 0, is zero less then 10000? if so, run whatever is in
the loop (meaning run whatever is in the curly brackets under the for
statement) and increment the counter value by one, then test again, (so
counter is now 1.) 1 is still less then 10000, so the loop runs again, and
counter becomes 2, which is still less then 10000 so the loop runs again,
and counter becomes 3.. and so on up till the counter is 10001, at which
point the middle expression is false, and the loop exits.
Not that complicated is it?
That's all there is to know about basic for loops. (Don't worry to much if
it's not all that clear now, it will become clearer when you see some
examples of them in action.)
"foreach" loops.
As far as Perl is concerned, "for" and "foreach" are interchangable, they mean the same thing.
The reason for having two names for the same thing is simple, it's just to make two possible
uses for them clearer from a linguistic perspective.
In the "for" loop example above, you saw how it is used to itinerate through a block of code a pre
specified number of times. Foreach is generally used to loop though a block of code that has no
preset number of itinerations. (for example looping though a file where you may not know how
many lines the file has, and therefore not knowing how many times to loop.)
The foreach loop will go though the file one line at a time till there are no more lines, then it
will exit and continue on with the script. (The While loop is somewhat similiar.)
The format if a foreach loop is pretty simple:
foreach my $single_item (list_item)
{
# Single item is stored in $single_item
}
In the above example, $single_item is a simple placeholder scalar variable designed to hold each single
value that together make up the list_item.
list_item in the above example can be an array, the keys or values of a hash, or an open filehandle.
basically anything that you want Perl to go though one item at a time and perform some function of each item
independently.
Defining a variable to contain the value of each loop itineration is not necessary, although it often
helps with making the code more readable. If you don't want to use a placeholder variable, each lines
data will be contained in the default Perl variable for such things, that variable is "$_".
Here is an example of the same loop above without using the placeholder variable.
foreach (list_item)
{
# Single item is stored in $_
}
As you can see, loops are pretty simple to write, and immensely useful.
Your likely to find that as you get better at Perl, looping when its necessary will become second nature.
"while" loops.
The while loop shares alot in common with the foreach loop, indeed the format is the same as well.
Here is an example of the layout of a while loop:
while(some item that returns true or false)
{
# perform some action here.
}
In the top parenthesis (the top brackets) is something that will return true or false, if its true, the code
in the bottom curly brackets will be executed, if false, it won't be.
If you put an array in there, or an open filehandle it will return true for each single item in the array or
filehandle, when it gets past the last item, it returns false and the loop ends.
Thats all there is to it, accept to say that in complex scripts you will often see nested loops, where one loop
might itinerate though an array of items, and each single item in the array is made up of other items,
so another loop will inside the loop and itenerate though the contents of each item of the outside loop.
That might sound complicated, but its really not, and it will make more sense when you see it in action.
Subroutines, (also known as functions by some).
Subroutines are very handy, but there isn't much specific explanation I can
give.. a sub is a piece of code you write yourself that you might want to
use many times in a script.. (the same reason you have functions in
JavaScript).
The idea is that you can write the code once, and use it many times in your script
rather then have the same code over and over each time you need it.
Checking HTML form data for valid characters might be one possible use of a subroutine.
It might also be a good reason to have a loop as well.
Lets use that as an example. Here is what we need to do.
Say that all your user submitted formdata (from a HTML form) is contained in a hash
called %old_formdata where the keys are the form names and the values are the actual data
the user entered in each form field.
Like so (for example.):
my %old_formdata = ('name' => 'Franki Hauptle', 'email' => 'franki@somedomain.com', 'city' => 'Perth Australia', 'PObox' => '1 2 5' )
So, say we want to loop though the hash keys, and replace any spaces in the values returned
with underscores.(Hey its an example, give me a break :-) and put the new data in a new hash
called %new_formdata with the same key names as the old hash.
Anyway, here is what we could do:
First we create a new hash to hold the new values we create, (which underscores instead of spaces).
Then we create the loop on the keys of the %old_formdata hash.
# create the new hash to hold the changed data. my %new_formdata; foreach my $key (keys %formdata) { # First get each keys value in the hash in turn and run it # though the sub, one at a time. my $new_value = replace_spaces($formdata{$key}); # Now put the new value (with no spaces) into the new hash # with the same key it had in the old hash. $new_formdata{$key} = $new_value; }
Then we create a simple subroutine that takes the key value passed to it, and replaces any spaces in it with an underscore and returns the new resultant value.
sub replace_spaces { # Get the value that was passed # to the the sub when it was called. my $form_value = shift; # Use a regex substitute to change the # spaces in each value to underscores. # Don't worry if you don't understand this # We cover regex later on. my $new__form_value = ($form_value =~ s/ /_/g); # Return the new value so it is assigned to # $new_value back in the loop up the top. return $new_form_value; }
Now that wasn't to hard was it? as always, it seems alot more complicated then it is.
Here is the break down in english.
First we loop though the keys of the hash, (which in this example are: name, email, city and PObox)
Then inside the loop we take each key in turn, and pass that keys value in the hash to the subroutine,
(replace_spaces), The subroutine takes the keys value passed to it, replaces the spaces with underscores
and returns the new changed value back to the variable the sub was called with.
(my $new_value = replace_spaces($formdata{$key});)
So each time the loop itinerates, $new_value contains the hashes values with all the spaces changed for
underscores, which are then inserted into the new %new_formdata hash we created above the foreach loop.
($new_formdata{$key} = $new_value;)
So there you go, that wasn't so difficult now was it?
The end result of the above code would be the %new_formdata hash containing this new data:
my %new_formdata = ('name' => 'Franki_Hauptle', 'email' => 'franki@somedomain.com', 'city' => 'Perth_Australia', 'PObox' => '1_2_5' )
Notice that all the spaces in the new hashes values are now underscores.
You might then have perl print that data out onto a html page, or email it to youself
or whatever you like.
Say for another example, you need the ability to change the format of a number of
variables in your script, (perhaps to change numeric values into
dollar/cents format prior to printing them to the users browser), you could
write the code over and over wherever you want to change a value, or you
could write the code once, put in in a subroutine, and then just call it
whenever you need to change a value..
The structure for a subroutine is very basic, it looks like this:
sub the_name_of_the_subroutine { # collect any info you passed to the sub my $data = shift; # If you pass more then one bit of data to the sub, you can do it # using the default Sub array @_ # (which Perl uses behind the scene when you pass data to a sub.) # The line below would take all the different bits of data you passed # to the sub and puts them in an array so you can play with them. # the array will only contain what you pass to it when calling the sub. # It might be a dozen items or only one. thats your call. my @data_array = @_; # Here you would do whatever you want with the data, you might use # a loop, if/else conditions or anything else. # Then at the end of the sub, you return whatever value or values # that are the results you want to give back to the main script return (some result value(s) if you wish to.); }
And when you want to use that code, you'd do something like this:
my $value = the_name_of_the_subroutine($Some_data, $some_more_data, $even_more_data );
Or if its just code that prints html or something else that doesn't return a value you want to catch in a variable. you can just start the sub like this:
&the_name_of_the_subroutine();
That's it.. Its abit more complicated then that, but that's the basics, and
you'll learn the rest when you see them in action in the coming example
primers. (and I will talk you though the examples.)
I don't want to over complicate the issue right now.. but here is an example
of a function I use that changes any numeric value into dollar/cent format.
Here is the sub, it would generally reside at the end of your script (but
it doesn't have to).
sub format_price { my $unformatted_price = shift; my $formatted_price = sprintf ("%.2f", $unformatted_price); return $formatted_price; }
Here is an example of how you would call the sub to change a value.
my $dollar_format_value = format_price($value_you_wish_to_change_to_dollar_format);
a real life calling of the sub, would look like this:
my $total_unformated = 25; my $formated_total = format_price($total_unformated);
And the result is that $formated_total is now equal to: 25.00 (which is the
value of $unformated_total put into double decimal point format.(if it
wasn't already)).
Again, this might look complicated, but its really not, once you see subs
working, it will all fall into place.
A good way to think of subroutines, is as mini programs that happen to be
contained in your script, they perform some function, they receive some input,
do something with that input, and return some final result.
A good sub is one that is passed everything it needs to do its job, and returns
only that which you needed to the main script its running from within.
Any variables inside the sub that are not returned, will cease to exist once the
sub has finished running (or they should if done properly), that minimizes memory
wastage and results in clean code.
so make sure any variables you create inside the sub are initialized with "my" so that
they disappear when they are no longer needed.
Thats all the explanation you need of subroutines at this point, their uses
will become clear as you start using them.
Cool Tip
If you learn Perl and you want to write ASP (Active Server Pages), you can
combine the two very nicely.
When you install Perl on a server supporting ASP, you can use PerlScript to
write ASP applications. So you can not only use Perl to write CGI
applications in the traditional sense, you can use it to achive the same
results that are so highly touted by users of PHP and Microsoft ASP.) in
other words, you can embed PerlScript directly into web pages in the same
manner as PHP and M$ ASP.
Some hosts even offer Apache::ASP, which is a version of Perl that runs inside
the web server and gives you exactly the same thing. Ask your host, you might have
this ability already available.
Also, keep in mind that everything I have shown you here doesn't just relate
to Perl, for/foreach, if/elsif/else, subroutines, regex and pretty much
everything else I have shown (or will show you) you relates to every
language, be it C, C++, JAVA, PHP, python, shell scripting and even nasty
languages like Visual Basic use the same basic practices.
Many universities teach Perl as the first language because its considered the
easiest to understand the principles that all languages use as their basis.
So if you get a good understanding of Perl, you will be well set to learn
the other languages much easier then if you were to start that language with
no prior knownledge of programming practices.
So if you are ready to learn more:
Back to the Tutorial Index