Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Phone Book

by h4ckroot (Initiate)
on Jan 04, 2009 at 18:18 UTC ( [id://734030]=perlquestion: print w/replies, xml ) Need Help??

h4ckroot has asked for the wisdom of the Perl Monks concerning the following question:

Hello all MOnks Out there :)... Actually i am new here as i am new to perl at all.. however i want to share some code i wrote seeking for your advice i was trying to write a script to a phonebook here is the code i wrote Please tell me any advices or better ways to modify it.
#!/usr/bin/perl -w open TEMPFH,"DB.txt" or die "Sorry Cant Open File...$!"; #reading the File For Getting the Last id To Support Auto increment.Th +ere is another way to do it later #using Tail . while(<TEMPFH>){ $_ =~/^(\d*).*$/; $ID=$1 if eof; } close TEMPFH; print "Welcome To My Simple Phone Book:)\n"; print "What Do You want me To Do\n"; while(1){ print "[L]ist,[A]dd,[D]elete,[Q]uit\n"; $userInput = <STDIN>; chomp $userInput; if (uc $userInput eq "L" or uc $userInput eq "LIST"){ open READFH,"DB.txt" or die "Sorry Cant Open the DataBase...$!"; for (<READFH>){ print; } close READFH; } elsif (uc $userInput eq "A" or uc $userInput eq "ADD"){ open WRITEFH,">>DB.txt" or die "Sorry Cant open The Database..$!"; while(<WRITEFH>){ print;} while(1){ print "Please enter the name\n"; print "Please Note that Only chars,numbers and underScore are aLlo +wed with max 30 char and min One Char \n"; chomp($name = <STDIN>); if ($name !~ /^\w{1,30}$/){ print "Sorry Invalid Name Try Again\n"; next; } else{last;} } while(1){ print "Please Enter The Number\n"; print "Please Note that Only Numbers are allowed With max 30 digit + and min 1 digit\n"; chomp($number=<STDIN>); if ($number !~ /^\d{1,30}$/){ print "Sorry Invalid Number..Try Again\n"; next; } else{last;} } $ID++; print WRITEFH "$ID:$name:$number\n"; print "Added Succefully\n"; close WRITEFH; } elsif(uc $userInput eq "Q" or uc $userInput eq "QUIT"){ print "Thank You,Keep Visiting :D\n"; last; } elsif(uc $userInput eq "D" or uc $userInput eq "DELETE"){ print "Please Enter the Name You Wana Delete\n"; chomp($userToDelete = <STDIN>); open DELETEFH,"DB.txt" or die "Sorry Couldnt Open DB...$!"; open TEMP,">temp.txt" or die "Sorry Couldnt Open DB...$!"; print "Successfully Deleted...\n"; $myid=1; while (<DELETEFH>){ if (/^\d:$userToDelete:\d*$/) { $ID--; next; } else{ $_ =~ /^\d*:(.*)$/; print TEMP "$myid:$1\n"; $myid++; } } close DELETEFH; close TEMP ; rename "temp.txt","DB.txt" ; $myid=1; } else{ print "Sorry Invalid Option...Try Again"; } print "\n"; }
i know i didnt use any pragmas here like strict. :D but anyway i wanted your notes and advices SO Please post your notes.. Thanks in advance..

Replies are listed 'Best First'.
Re: Phone Book
by jethro (Monsignor) on Jan 04, 2009 at 19:36 UTC

    Strict and consistent indentation are the first things I would change. Also you should have empty lines only at places where you want a visual separation. In short your code makes a very bad first impression

    Also you have one long meandering procedure which is not easy to read. Refactor your code into subroutines, in your case you might put the list,add and delete functions into separate subroutines.

    The .*$ at the end of the first regexp is useless.

    You don't seem to have any use for your ID. And if your phone book never has more than a few 1000 entries you could always read the complete database into memory, into an array and have the index as id number. If it might get bigger you should use a real database engine.

Re: Phone Book
by apl (Monsignor) on Jan 04, 2009 at 20:17 UTC
    In addition to the other advice you've received:
    • Put the code to prompt for a user name in a common subroutine. You can always pass a descriptive phrase ('to add', 'to delete') as a parameter.
    • Open DB.txt once at the start of your code, and (if necessary) back up the old file and write the new file once at the end of your program (preferably in a subroutine). This enables you to remove multiple FH names.
Re: Phone Book
by Herkum (Parson) on Jan 04, 2009 at 19:14 UTC
    Break up your Choice logic so that it calls subroutines that do the actual work. It will make your code easier to understand if you do this,
    $userInput = <STDIN>; chomp $userInput; $userInput = uc $userInput; # you could probably do this on the STDIN, but I am not sure. # Another monk should be able to tell you. ( $userInput eq 'L' or $userInput eq 'LIST' ) ? list_phone_book() : ( $userInput eq 'A' or $userInput eq 'ADD' ) ? add_to_phone_book +() : ( $userInput eq 'D' or $userInput eq 'DELETE') ? delete_from_phone +_book() : ( $userInput eq 'Q' or $userInput eq 'QUIT' ) ? quit_phone_book() : unknown_selection +();

    As it stands now, you would have read your whole script line by line to figure out where you are going for your selections. With the above code, you know where to look for each selection and what it is supposed to do.

    You are also doing a bunch of open and closes all over the place, I beat your could get rid of a bunch of code by breaking those down in subroutines.

      $userInput = <STDIN>; chomp $userInput; $userInput = uc $userInput;

      can be written (more concisely) as

      chomp(my $userInput = uc <STDIN>);

      Also, I think there may be a better method to running each subroutine than using multiple conditional operators. Perhaps a dispatch table will do.

      my %pbactions = ( L => \&list_phone_book, LIST => \&list_phone_book, A => \&add_phone_book, ... ); # Later on~ defined $pbactions{$userInput} ? $pbactions{$userInput}->() : usage();

      Untested lines of code, they're just to inspire.

      And you didn't even know bears could type.

Re: Phone Book
by GrandFather (Saint) on Jan 04, 2009 at 23:06 UTC

    Just a little less work gets you a crude GUI version:

    use strict; use warnings; use Tk; my $obj = bless {}; # Create an object to make passing parameters easi +er and to # maintain state. Generally considered better than using global va +riables. if (open my $tempIn, '<', "DB.txt") { while (<$tempIn>) { chomp; my ($name, $number) = split ':'; next unless defined $number; #Skip empty or corrupt lines $obj->{phoneBook}{$name} = $number; } close $tempIn; } $obj->{main} = MainWindow->new (-title => 'My Simple Phone Book'); $obj->{main}->Button (-text => 'List', -command => [\&doList, $obj])-> +pack (); $obj->{main}->Label (-text => "Name:")->pack (); $obj->{main}->Entry (-textvariable => \$obj->{name})->pack (); $obj->{main}->Button (-text => 'Del', -command => [\&doDel, $obj])->pa +ck (); $obj->{main}->Label (-text => "Number:")->pack (); $obj->{main}->Entry (-textvariable => \$obj->{number})->pack (); $obj->{main}->Button (-text => 'Add', -command => [\&doAdd, $obj])->pa +ck (); $obj->{main}->Button (-text => 'Exit', -command => [\&doExit, $obj])-> +pack (); MainLoop (); sub doAdd { my ($self) = @_; $self->{phoneBook}{$self->{name}} = $self->{number}; } sub doExit { my ($self) = @_; open my $out, '>', "DB.txt" or die "Sorry Cant Open File: $!"; for my $name (sort keys %{$self->{phoneBook}}) { print $out "$name:$self->{phoneBook}{$name}\n"; } close $out; exit; } sub doDel { my ($self) = @_; delete $self->{phoneBook}{$self->{name}}; } sub doList { my ($self) = @_; my $msg; for my $name (sort keys %{$self->{phoneBook}}) { $msg .= sprintf "%-20s %20s\n", $name . ':', $self->{phoneBook +}{$name}; } $self->{main}->messageBox ( -icon => 'info', -message => $msg, -title => 'Phone numbers', -type => 'Ok', ); }

    Note that the data is maintained in memory until the program exits.


    Perl's payment curve coincides with its learning curve.
      thanks guys for all your advices....i will re organize it and re post it...again..thanks in advance.
Re: Phone Book
by Anonymous Monk on Jan 04, 2009 at 18:44 UTC
    i know i didnt use any pragmas here like strict.:D but anyway i wanted your notes and advices SO Please post your notes..
    Great, you know your biggest problem, add use strict and go fix it.
Re: Phone Book
by fmerges (Chaplain) on Jan 04, 2009 at 21:25 UTC

    Hi,

    Also take a look at IO::Prompt

    Regards,

    fmerges at irc.freenode.net
Phone Book After Modifications
by h4ckroot (Initiate) on Jan 05, 2009 at 14:29 UTC
    Hi Guys i just made some modifications that you suggested me and here is the code again,Please any advices or improvements are more than welcomed.
    #!/usr/bin/perl -w use strict; my $ID; my $userInput; open TEMPFH,"DB.txt" or die "Sorry Cant Open File...$!"; #reading the File For Getting the Last id To Support Auto increment.Th +ere is another way to do it later #using Tail . while(<TEMPFH>){ $_ =~/^(\d*).*$/; $ID=$1 if eof; } close TEMPFH; print "Welcome To My Simple Phone Book:)\n"; print "What Do You want me To Do\n"; while(1){ print "[L]ist,[A]dd,[D]elete,[Q]uit\n"; chomp($userInput = <STDIN>); if (uc $userInput eq "L" or uc $userInput eq "LIST"){ &list($ID); } elsif (uc $userInput eq "A" or uc $userInput eq "ADD"){ &add($ID); } elsif(uc $userInput eq "Q" or uc $userInput eq "QUIT"){ print "Thank You,Keep Visiting :D\n"; last; } elsif(uc $userInput eq "D" or uc $userInput eq "DELETE"){ &delete($ID); } else{ print "Sorry Invalid Option...Try Again"; } print "\n"; } ###################################################################### +################################################# sub add{ open WRITEFH,">>DB.txt" or die "Sorry Cant open The Database..$!"; my $name; my $number; while(1){ print "Please enter the name\n"; print "Please Note that Only chars,numbers and underScore are aLlo +wed with max 30 char and min One Char \n"; chomp($name = <STDIN>); if ($name !~ /^\w{1,30}$/){ print "Sorry Invalid Name Try Again\n"; next; } else{ last; } } while(1){ print "Please Enter The Number\n"; print "Please Note that Only Numbers are allowed With max 30 digit + and min 1 digit\n"; chomp($number=<STDIN>); if ($number !~ /^\d{1,30}$/){ print "Sorry Invalid Number..Try Again\n"; next; } else{ last; } } $_[0]++; print WRITEFH "$_[0]:$name:$number\n"; print "Added Succefully\n"; close WRITEFH; } sub delete{ my $currentID=$_[0]; my $userToDelete; my $myid=1; print "Please Enter the Name You Wana Delete\n"; chomp($userToDelete = <STDIN>); open DELETEFH,"DB.txt" or die "Sorry Couldnt Open DB...$!"; open TEMP,">temp.txt" or die "Sorry Couldnt Open DB...$!"; while (<DELETEFH>){ if (/^\d*:$userToDelete:\d*$/i) { $_[0]--; next; } else{ $_ =~ /^\d*:(.*)$/i; print TEMP "$myid:$1\n"; $myid++; } } if($_[0] < $currentID){ print "Successfully Deleted user:$userToDelete\n"; } else{ print "Error..Deleting User Please Check the username Again..,\n"; } close DELETEFH; close TEMP ; rename "temp.txt","DB.txt" ; $myid=1; } sub list{ open READFH,"DB.txt" or die "Sorry Cant Open the DataBase...$!"; for (<READFH>){ print; } close READFH; }
    Thanks in advance.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://734030]
Approved by kyle
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2025-11-13 21:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your view on AI coding assistants?





    Results (69 votes). Check out past polls.

    Notices?
    hippoepoptai's answer Re: how do I set a cookie and redirect was blessed by hippo!
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.