Perl - Making It Fair for the Rest

To be fair to everyone else who has access to your program, before we look up the name in the table, we need to grab the first word of whatever's entered by that person and

There are at least three ways to accomplish this task in Perl.  This time we'll do it using two operators:  the substitute operator, which finds a regular expression and replaces it with a string, and the translate operator, to put the string in lower case; and a Perl built-in function, ucfirst, which returns a version of a string with the first character capitalized.

First, the substitute operator:  we want to take the contents of $name, find the first nonword character, and zap everything from there to the end of the string.  /\W.*/ is the regular expression we are looking for:  the \W stands for a nonword character (something other than a letter, digit, or underscore), and .* means any characters from there to the end of the line.  Now, to blow these characters away, we need to take whatever part of the string matches this regular expression and replace it with nothing:

	$name =~ s/\W.*//;

We're using the same =~ operator that we did before, but now on the right we have a substitute operator:  the letter s followed by a slash-delimited regular expression and string.  (The string in this example is the empty string between the second and third slashes.)  This operator looks and acts very much like the substitutions of the various UNIX editors.

Now, to get whatever's left into lowercase, we translate the string using the tr operator (if you were expecting characters with accent marks, then you'd want to use the uc [uppercase] function instead of tr; we'll probably be using the uc function in a later lesson [and, of course, the mention of an "uppercase" function, leads me to believe that Perl probably has a "lowercase" function also; we'll most likely be using that function in a later lesson too).  It looks a lot like a UNIX tr command, taking a list of characters to find and a list of characters to replace them with.  For our example, to put the contents of $name in lowercase, we use:

	$name =~ tr/A-Z/a-z/;

The slashes delimit the searched-for and replacement character lists.  The dash between A and Z stands for all of the characters in between, so we have two lists that are each twenty-six characters long.  When the tr operator finds a character from the string in the first list, the character is replaced with the corresponding character in the second list.  So all uppercase J's become lowercase j's, and so on.

Now, for the concluding ucfirst function.  We want to take the first character of $name and make it upper-case.  Using the ucfirst function, it looks like this:

	$name = ucfirst($name);

Putting all of this together with the rest of the program, we get:

#!/usr/bin/perl -w
%words = qw(
	Jason	camel
	Michele	llama
	Tracey	alpaca
	Karee	pea
	Patrick	alpaca
);
print "What is your name? ";
$name = <STDIN>;
chomp ($name);
$original_name = $name;					# save for greeting
$name =~ s/\W.*//;					# zap everything after the first word
$name =~ tr/A-Z/a-z/;					# lowercase everything
$name = ucfirst($name);					# capitalize the first character
if ($name eq "Larry") {					# OK to compare this way now
	print "Hello, Larry!  How good of you to be here!\n";
}
else {
	print "Hello, $original_name!\n"; 		# ordinary greeting
	$secretword = $words{$name};			# get the secret word
	if ($secretword eq "") {			# oops, not found
		$secretword = "mfd";			# now, there's a secret word
	}
	print "What is the secret word? ";
	$guess = <STDIN>;
	chomp ($guess);
	while ($guess ne $secretword) {
		print "Wrong, try again.  What is the secret word? ";
		$guess = <STDIN>;
		chomp ($guess);
	}						# end of while not correct
	print "Good guess!  Have a great day!!";
}

Notice how the regular expression match for Larry (your name in your program) became a simple comparison again.  After all, both Larry Boatman and larry become Larry after the substitution, translation, and function.  And everyone else gets a fair ride, because Tracey and tracey george both become Tracey, etc.

With just a few statements, we've made the program much more user-friendly.  You'll find that expressing complicated string manipulation with a few keystrokes is one of Perl's many strong points.

However, hacking away at the name so that we could compare it and look it up in the table destroyed the name that was entered.  So, before the program hacks on the name, it saves it in $original_name.  (Like C symbols, Perl variable names consist of letters, digits, and underscores and can be of nearly unlimited length.)  We can then make references to $original_name later in the program.

As stated at the outset of this lesson, Perl has many ways to mangle and monitor strings.  We'll be looping through regular expressions and other data transformations again in future lessons.

Now that we've added so much to the code, we have to scan through many detailed lines before we can get the overall flow of the program.  What we need is to separate the high-level logic (asking for a name, looping based on entered secret words) from the details (comparing a secret word to a known good word).  We might do this for clarity, or maybe because one person is writing the high-level part and another is writing (or has already written) the detailed parts.  What do you suppose the necessary programming elements are to accomplish these tasks?  See you next lesson!