I've been dilgently working my way through Laura Lemay's book
Sams Teach Yourself Perl in 21 Days, and doing all the exercises at each stage. Each time I would find a bug, I would stop and not continue until I'd solved it. I've now finished chapter (day) 8 and I'm unwilling to continue, as I'm stumped by a script called morenames.pl.
This script takes its input from a list of names in a text file which I called namefile.txt. It presents you with a menu to sort the names in alpha-betical order by firstname or surname, to search for a name in the file or to exit.
The 2 sorting parts and the exit part all work fine, however it is the search part that's giving me trouble. Here is a copy of the name list I made up;
namefile.txtDon Donzal
Chris Gates
Kirby Tucker
Ole DB
Kris Teason
Manu Zacharia
Ed Skoudis
HD Moore
Johnny Long
Oneeyed Carmen
Bill V
Role Reversal
Jim Bob
Slim Jim
Black Azarro
Gordon Lyon
Salvatore Sanfilippo
Joanna Rutkowska
Linus Torvalds
Bill Joy
Larry Wall
Dennis Ritchie
Richard Stallman
And here is a copy of the script;
morenames.pl#!/usr/bin/perl -w
#This script reads names from a file.
#It offers a menu with which you can sort the names, or search them.
%names = (); #hash of names
@raw = (); #raw words
$fn = ""; #first name
$exit = 1; #exit program
$in = ''; #temporary in
@keys = (); #temporary keys
@n = (); #temporary name
$search = ''; #thing to search for
while (<>) {
chomp;
@raw = split(" ", $_);
if ($#raw == 1) { #regular case
$names{$raw[1]} = $raw[0];
} else { #build a firstname
$fn = "";
for ($i = 0; $i < $#raw; $i++) {
$fn .= $raw[$i] . " ";
}
$names{$raw[$#raw]} = $fn;
}
}
while ($exit) {
print "\n1. Sort names by last name\n";
print "2. Sort names by first name\n";
print "3. Search for a name\n";
print "4. Quit\n\n";
print "Choose a number: ";
chomp ($in = <STDIN>);
if ($in eq '1') { #sort and print by last name
foreach $name (sort keys %names) {
print "$name, $names{$name}\n";
}
} elsif ($in eq '2') { #sort and print by first name
@keys = sort { $names{$a} cmp $names{$b} } keys %names;
foreach $name (@keys) {
print "$names{$name} $name\n";
}
} elsif ($in eq '3') { #find a name (1 or more)
print "Search for what? ";
chomp($search = <STDIN>);
while (@n = each %names) {
if (grep /$search/, @n) {
$keys[++$#keys] = $n[0];
}
}
if (@keys) {
print "Names matched: \n";
foreach $name (sort @keys) {
print " $names{$name} $name\n";
}
} else {
print "None found.\n";
}
@keys = (); #undefine keys for next search
} elsif ($in eq '4') { #quit
$exit = 0;
} else {
print "Not a good answer. 1 to 4 please.\n";
}
}
OK, so I run the script by typing morenames.pl namefile.txt in Linux or perl morenames.pl namefile.txt in Windows (I tested both) and choose option 3. When I get asked what to look for I type ch, but the output I get is all the names but with the names including lower case ch doubled. When I redo the test I get the correct output, but still in lower case only.
1. Sort names by last name
2. Sort names by first name
3. Search for a name
4. Quit
Choose a number: 3
Search for what? ch
Names matched:
Black Azarro
Jim Bob
Oneeyed Carmen
Ole DB
Don Donzal
Chris Gates
Slim Jim
Bill Joy
Johnny Long
Gordon Lyon
HD Moore
Role Reversal
Dennis Ritchie
Dennis Ritchie
Joanna Rutkowska
Salvatore Sanfilippo
Ed Skoudis
Richard Stallman
Richard Stallman
Kris Teason
Linus Torvalds
Kirby Tucker
Bill V
Larry Wall
Manu Zacharia
Manu Zacharia
1. Sort names by last name
2. Sort names by first name
3. Search for a name
4. Quit
Choose a number: 3
Search for what? ch
Names matched:
Dennis Ritchie
Richard Stallman
Manu Zacharia
I would expect this second output the first time around. Note there is a line at the end of the loop @keys = (); Which is supposed to undefine keys for next search.
I would also expext to find
Chris Gates in that list too. I tried using grep -i like I would in UNIX to ignore case sensitivity but Perl got very cross with me for doing this.

Evidently grep works differently in Perl than the way it does in UNIX. I also tried many lc and uc functions on the $name, $raw and $search variables but with no success.
So my questions are;
1. How can I change the script so that the search will be case insensitive?
2. Why does the script need 2 iterations to give me decent output?
I've searched the internet for fixes of this script and found none. I will probably find an answer to this in later chapters, but I'm stubborn and want to find this out before continuing with the info I have from the chapters until now.
BTW, I was using Perl 5.8.8 on BackTrack 2 , and ActiveState Perl 5.8.8 on Windows XP Pro if that interests anyone.