.

morenames.pl

<<

Negrita

User avatar

Sr. Member
Sr. Member

Posts: 299

Joined: Sat Sep 10, 2005 5:45 pm

Location: /dev/null

Post Sat Jun 07, 2008 5:51 pm

morenames.pl

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.txt
  Code:
Don 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
  Code:
#!/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.

  Code:
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.
Last edited by Negrita on Sat Jun 07, 2008 6:19 pm, edited 1 time in total.
CEH, CCSA NG/AI, NNCSS, MCP, MCSA 2003

There are 10 kinds of people, those that understand binary, and those that don't.
<<

shakuni

Jr. Member
Jr. Member

Posts: 80

Joined: Sun Nov 04, 2007 2:24 pm

Post Sun Jun 08, 2008 7:12 am

Re: morenames.pl

1. How can I change the script so that the search will be case insensitive?

  Code:
while (@n = each %names) {
         if (grep /$search/i, @n) {
            $keys[++$#keys] = $n[0];
         }
      }

/i makes the search case-insensitive. So now you can find Chris Gates.
2. Why does the script need 2 iterations to give me decent output?

Works fine in the first iteration on my system. Thus the problem may be somewhere in you system and not in the script.
There is no rule, law or tradition that apply universally... including this one.
<<

Negrita

User avatar

Sr. Member
Sr. Member

Posts: 299

Joined: Sat Sep 10, 2005 5:45 pm

Location: /dev/null

Post Sun Jun 08, 2008 6:21 pm

Re: morenames.pl

Thanks shakuni, you've been more help than you realise. Firstly the /i switch works great - Chris Gates has now been found.  :P

Your remark about the script working fine on your system, and it beeing a problem on my system got me thinking. The thing is I had tried this on both my home PC and on my laptop from work and got the same result, before posting here.

So I got to thinking about how I had been running the script and how you had probably run it. When I ran the script I would go through the menu in numerical order to make sure all the options worked. I then thought that you had only tried option 3 in the menu. I did some testing and I found that when choosing option 3 it works fine but when choosing option 2 (Sort names by first name) before option 3 the result would be the entire list and the chosen search string doubled.

I looked at the code and found that in the loop for option 2 the array @keys is used but it is not undefined before option 3 begins. Obviously in option 3 $search is being added to @keys and this is giving the result I was getting. I managed to solve this by moving @keys = (); to the top of the loop for option 3.

The script is now working perfectly. For all those that didn't understand what I wrote above and want to know, the loop for option 3 now looks like this;

  Code:
} elsif   ($in eq '3') { #find a name (1 or more)

      print "Search for what? ";
      chomp($search = <STDIN>);

      @keys = (); #undefine keys for next search

      while (@n = each %names) {
         if (grep /$search/i, @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";
      }
CEH, CCSA NG/AI, NNCSS, MCP, MCSA 2003

There are 10 kinds of people, those that understand binary, and those that don't.

Return to Programming

Who is online

Users browsing this forum: No registered users and 0 guests

.
Powered by phpBB® Forum Software © phpBB Group.
Designed by ST Software