Perl language: Part III

String manipulations, Unix functions from Perl, Associative Arrays

We have learnt how to store scalar variables and arrays. In this lab, we shall see the third useful data structure: Associative arrays (hashes).
Also, since the power of perl is in manipulation of strings for generating reports, or HTML files, we will learn the most common string manipulation utilities. In particular, we concentrate on the following:
1. Joining Strings using the "." operator
2. Matching (searching) for patterns in a string using m/PATTERN/
3. Substituting (find/replace) one expression for another using s/OLD/NEW/


Example1.pl
#!/usr/local/bin/perl

$a_string = "Perl is simple.";

$b_string = "I love it!";

$join_string = $a_string . $b_string;

print $join_string;
print "\n";

# the '.' operator can be used many times, with variable or constant strings:
$nicer = $a_string . " " . $b_string;
print $nicer;
print "\n";

NOTES:
When you want to join two strings, use the dot operator, ".", as in this example. Recall that you can break any string using the split function.


Example2.pl
#!/usr/local/bin/perl

$line = <STDIN>;
chop ($line);
@words = split(/[ \t]+/, $line);
$index = 0;
while ( $index < @words) {
      print ("$words[$index]\n");
      $index++;
}
print( "\n");

NOTES:
This is a useful example. Here, the split function works as follows:
It searches for any character between the square brackets. In the example, there are two characters inside '[' and ']': " " (space), and '\t' (tab). The '+' sign following the square brackets is used to indicate one or more consecutive occurences of any characters inside the '[' and ']'. In this case, the variable $line will be split wherever there is any combination of spaces and tabs.


Example3.pl
#!/usr/local/bin/perl

$_ = "Bus 298 goes to Lam Tin every 20 minutes";

if ( m/Lam Tin/) {
    print ("Found a bus to Lam Tin !\n");
}
else  { print ( "No bus to Lam Tin.\n"); }

if ( m/Choi Hung/) {
    print ("Found a bus to Choi Hung.\n");
}
else  { print ( "No bus to Choi Hung.\n"); }


NOTES:
The matching operator, m/PATTERN/ will return TRUE if PATTERN matches a patern in a variable called $_. The $_ is a special variable which is used for all pattern matches for the mathing (m//) and substitute (s///) operators.
The match operator can use UNIX regular expression syntax modifiers. Most useful are the following:
m/PATTERN/g will do a Global search (find all occurences) of PATTERN in the variable $_. since there ma be more than one matches, it returns an array, with each successful match as elements.
m/PATTERN/i will Ignore the case (lower case, upper case) when matching.
You can use the 'i' and 'g' specifications together also, as in the next example.


Example4.pl
#!/usr/local/bin/perl

$_ = "UPPER CASE ? lower case ? Mixed CaSe ? No Problem !";

@case_instances = m/case/ig;

foreach $c (@case_instances) {
    print ("$c \n");
}



NOTES:
1. The use of "i" ignores the case while matching.
2. The use of "g" causes Global match (every instance); Note also that the match operator can be used to directly return an array !
3. Some useful matching patterns include matching word characters (any alphanumeric character, or the underscore) using \w, multiple word characters (that is, a single word) using \w+, single space character using \s, non-word characters (punctuation marks) using \W, tabs using \t, newline using \n etc.


Example5.pl
#!/usr/local/bin/perl

$_ = "I love Jackie Chan movies! I love kung-fu movies.";
print "$_ \n";

s/love/HATE/;
print( "$_ \n");

s/(HATE|love)/Admire/g;
print( "$_ \n");

s/admire/dislike/ig;
print( "$_ \n");

s/dis//g;
print( "$_ \n");


NOTES:
This example shows several features of the substitute operator.
1. Just like the match operator, the substitution is done on the value of a variable called $_.
2. The s/OLD/NEW/ will replace the FIRST OCCURENCE of "OLD" with "NEW".
3. The vertical bar, "|", is used to denote alternatives. It may be used many times in the same expression.
4. As for the match operator, you may use "g" and "i" filters.
5. Notice how "s/dis//g works: Every occurence of pattern "dis" is replaced by a null string.


Example6.pl
#!/usr/local/bin/perl

print ( "Enter a short password: ");
system ( "stty -echo");

# read the password, but it will not be printed to the screen !
$password = <STDIN>;

chop( $password);

print( "\nTo turn on the screen, type the password again: ");

$password_match = 0;

$n_tries = 0;

while ( ($n_tries < 3) && ($password_match == 0)) {
   $trial = <STDIN>;
   chop ($trial);
   if ($trial eq $password) { $password_match = 1;}
   else { print( "\nPassword does not match. Please re-type: "); }
   $n_tries++;
}

if ($password_match == 1) {
    print( "\nPassword matches !\n");
}
else {
    print( "\nSorry, your password was not correct !\n");
}
system( "stty echo");
      
 

NOTES:
1. Notice that ANY unix function can be called from perl, using:
system ( "UNIX-function-name arguments")
2. In this case, we call a Unix function: "stty", with argument "-echo". stty can be used to set terminal characteristics. With the argument "-echo", it causes the effect that what you type will not be printed on the screen.
3. Note that other functions can still print output to the screen; therfore the call to print still works after terminal echo is turned off. However, at the end of the program, if you do not turn terminal echo ON again (using "stty echo"), Unix may not show what you type on the screen after your program has completed execution.


Example7.pl
#!/usr/local/bin/perl

%hobbies = ( "ajay", "tennis",
             "ivan", "basketball",
             "william", "swimming");

print ("Ivan's hobby is: ", $hobbies{"ivan"}, "\n");

# this is a nice way to format the printing of a hash:
while ( ($key, $value) = each %hobbies) {
    print "$key = $value\n";
}

# this is how you set new values into a hash:
$hobbies{"jack"} = "soccer";

# this is how you delete a KEY (and its VALUE) from a hash:
delete $hobbies{"ajay"};

# and check if it works:
print "\nThe modified hash values are:\n";
while ( ($key, $value) = each %hobbies) {
    print "$key = $value\n";
}

NOTES:
1. We have learnt storing scalar variables (numbers, strings...) in $variable.
We also saw how to store an array of variables in @array.
Here, we see the third useful structure for storing data, an associative array (also called a 'hash').
2. You can think of a hash as an array, with the following difference:
an array is a list of variables, each with a name that looks like: array[i], where 'i' is the subscript value, such as 0, 1, 2, ...etc.
A hash is a list of variables, with specific names (also called 'keys'). Each 'key' has an associatee value. The hash is stored as follows:
( Key1, Value-Of-Key1, Key2, Value-of-Key2, ..., KeyN, Value-of-KeyN).
If you want to get the value of 'Key5' from the hash called "%myHash", you must urefer to: $myHash{ "Key5"}
For example, in the example, the key "ajay" has value "tennis", while the key "ivan" has the value "basketball".
3. When you work with the output of a database, you wil store the resulting table in an array; when you work with inputs from a FORM, you will store the values of these inputs in a hash.

Therefore, arrays and hashes are the most useful structures for writing cgi's linked to databases.


Exercises:

1. Hashes.
Write a perl function that will do the following:
(a) Ask the user to input a course name;
(b) Ask the user to input the course instructor;
(c) Store the input from (a) as key, and the input from (b) as the value of the key, in a hash called %course_info;
(d) Repeat (a), (b) and (c) until the user enters "done".

(e) Ask the user to enter a course name;
(f) If the instructor's name for this course contains the string "aj" (ignore case when matching) , print "This is a fun course"; otherwise print "I prefer DB!".

2. First create a file called nba.txt with the following contents:

Player			Team
===============================
Grant Hill		Pistons
Shaquille Oneal		Lakers
Karl Malone		Jazz
Chris Webber		Sixers
Allen Iverson		Kings
Gary Payton		Sonics
Sharif Abdur Rahim	Grizzlies

(a) Read the data into an array with each line as an element of the array.
(b) The player called Webber will change teams with the player called Iverson. Using the match and the substitute operators, make the necessary changes in your array.
(c) Print out the names of the players and their teams, arranged in alphabetical order by first name, in an HTML format file.
HINTS:
Your file must begin with the line:
<HTML>
and end with the line
</HTML>
Also, your file must make sure the columns are aligned properly. The easiest way to do so is to print each line as preformatted, using the html mark-ups
<PRE> LINE-OF-TEXT </PRE> <BR>