MikeyG has asked for the wisdom of the Perl Monks concerning the following question:
Below is my entire script, the problem I have is with Choice number 4.
#! /usr/bin/perl -W
use strict;
use 5.010;
my %accounts = (tom => "BigApple");
my %types = (tom => "admin");
my $choice;
my ($userID, $passwd, $type);
my @userID = $userID;
my $menu = <<MENU;
System Administration Tasks
1- Create a new account
2- Delete an account
3- Change an account password
4- List users in alphabetical order
5- Exit the system
MENU
while (1) {
print $menu, "\n";
print "Make your choice: ";
chomp($choice = <STDIN>);
if ($choice == 1){
print "Enter your userID: ";
chomp ($userID = <STDIN>);
print "Enter your password: ";
chomp ($passwd = <STDIN>);
if (exists $accounts{$userID}) {
print "Duplicate user id, try again later"
}else {
print "Enter the account type, admin (or regular): ";
chomp ($type = <STDIN>);
$accounts{$userID} = $passwd;
$types{$userID} = $type;
print "Account was successfully created \n";
}
} elsif ($choice == 4){
# sort the users in descending order
foreach $userID (reverse sort keys %accounts) {
# print out login names 3 per line
@keys = keys %accounts;
for (my $counter = 1; $counter <= @keys; $counter++)
{
print "$userID\t";
print "\n" if $counter % 3 == 0;
}
}
} else {
print "Invalid choice, TRY AGAIN!\n";
}
}
Original code restored below by GrandFather
#! /usr/bin/perl -W
use strict;
use 5.010;
sub heading;
# A script that allows a user to perform system administration tasks
# Programmer name: Michael A. Gregor
# Course: COSC 146
# Lab#: 7
# Due Date: 3/10/16
# lab7.pl
my %accounts = (tom => "BigApple");
my %types = (tom => "admin");
my $choice;
my ($userID, $passwd, $type);
my @userID = $userID;
# call the function named 'heading' to display the output heading
heading;
my $menu = <<MENU;
System Administration Tasks
1- Create a new account
2- Delete an account
3- Change an account password
4- List users in alphabetical order
5- Exit the system
MENU
while (1) {
# display the menu
print $menu, "\n";
# get the user choice and fullfil the request
print "Make your choice: ";
chomp($choice = <STDIN>);
if ($choice == 1){
#print "a\n"; # replace the print-statements with your own code !!
+!!!!!!!!!!!!!!!
# get user id and password
print "Enter your userID: ";
chomp ($userID = <STDIN>);
print "Enter your password: ";
chomp ($passwd = <STDIN>);
# is there an account by that name already? if so, display a messa
+ge and then start the next loop iteration
if (exists $accounts{$userID}) {
print "Duplicate user id, try again later"
}
# no account by that name, ask the user for the account type
else {
print "Enter the account type, admin (or regular): ";
chomp ($type = <STDIN>);
# create the account and then print a message
$accounts{$userID} = $passwd;
$types{$userID} = $type;
print "Account was successfully created \n";
}
} elsif ($choice == 2){
# get user id and password
print "Enter your userID: ";
chomp ($userID = <STDIN>);
print "Enter your password: ";
chomp ($passwd = <STDIN>);
# authenticate the user account. If it is a valid account with
+ admin privileges, go ahead and delete the
# account. If the account is invalid or has no admin privieges
+, display an appropriate message in each case
if (authenticate($userID, $passwd, %accounts) == 1) {
if ($type eq 'admin') {
delete $accounts{$userID};
print "Account was deleted successfully";
} else {
print "Can't delete, Contact the system administrator"
+;
}
}
} elsif ($choice == 3){
# get user id and password
print "Enter your userID: ";
chomp ($userID = <STDIN>);
print "Enter your password: ";
chomp ($passwd = <STDIN>);
# authenticate the user account. If it is a valid account, ask
+ the user for the new password.
# have the user re-enter the new password again and confirm th
+at they are the same. If so, change
# the password. In any case, print a appropriate message
if (authenticate($userID, $passwd, %accounts) == 1) {
print "Enter a new password: ";
chomp (my $passwd = <STDIN>);
print "re-enter the password again: ";
chomp (my $npass1 = <STDIN>);
if ($passwd eq $npass1) {
$passwd = $npass1;
$accounts{$userID} = $passwd;
print "password was changed successfully";
} else {
print "password was not changed!";
}
}
} elsif ($choice == 4){
# sort the users in descending order
foreach $userID (reverse sort keys %accounts) {
# print out login names 3 per line
@keys = keys %accounts;
for (my $counter = 1; $counter <= @keys; $counter++)
{
print "$userID\t";
print "\n" if $counter % 3 == 0;
}
}
} elsif ($choice == 5){
# print a message and terminate the script
print "Good bye! \n\n";
exit;
} else {
print "Invalid choice, TRY AGAIN!\n";
}
}
# write a function definition for the function named 'heading'. This f
+unction prints out the output heading
sub heading {
print "\n";
print "Programmer name: Michael A. Gregor \n";
print "Course: COSC 146 \n";
print "Lab#: 7 \n";
print "Due Date: 3/10/16 \n";
}
# authenticate a user. return 1 if the user id and password combinatio
+n is good. Otherwise return 0;
sub authenticate {
my $id = shift;
my $passwd = shift;
my %accounts = @_;
if (exists $accounts{$id} && $accounts{$id} eq $passwd){
return 1;
} else {
return 0;
}
}
Re: How do you sort keys of a hash in descending order and print 3 per line?
by bangor (Monk) on Mar 16, 2016 at 01:27 UTC
|
I think you are trying too hard :)
my %accounts = (
tom => "BigApple",
tom2 => "BigApple2",
tom3 => "BigApple3",
tom4 => "BigApple4",
tom5 => "BigApple5",
tom6 => "BigApple6",
tom7 => "BigApple7",
);
# sort the users in descending order
my $counter = 1;
for my $userID (reverse sort keys %accounts) {
print "$userID\t";
print "\n" if $counter++ % 3 == 0;
}
tom7 tom6 tom5
tom4 tom3 tom2
tom
| [reply] [d/l] |
|
#!/usr/bin/perl
use warnings;
use strict;
my %accounts = (
tom => "BigApple",
tom2 => "BigApple2",
tom3 => "BigApple3",
tom4 => "BigApple4",
tom5 => "BigApple5",
tom6 => "BigApple6",
tom7 => "BigApple7",
);
my @keys = reverse sort keys %accounts;
print join ("\t", @$_), "\n" while @$_ = splice @keys, 0, 3;
Prints:
tom7 tom6 tom5
tom4 tom3 tom2
tom
Premature optimization is the root of all job security
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] [d/l] |
|
|
|
|
He's a monk, not a clairvoyant!
Please post the relevant line of code that the error is pointing you to :-)
The way forward always starts with a minimal test.
| [reply] |
Re: How do you sort keys of a hash in descending order and print 3 per line?
by 1nickt (Canon) on Mar 16, 2016 at 01:09 UTC
|
Your program doesn't compile as posted. You have an undeclared variable in there.
Your main problem is that you have nested for loops that cause the program to print each name the number of times there are items in the list. You need to consolidate the two things you are doing in loops so that you only loop through the names once, using the same loop for your counter.
Hope this helps!
Edit: Updated answer
The way forward always starts with a minimal test.
| [reply] |
Re: How do you sort keys of a hash in descending order and print 3 per line?
by Marshall (Canon) on Mar 16, 2016 at 04:53 UTC
|
Please, don't remove code after you post it.
I made a few mods that you might find instructive. And added an undocumented option 6. Add a few accounts and see what that does!
#!/usr/bin/perl -W
use strict;
use 5.010;
use Data::Dumper;
my $heading = <<HEAD;
A script that allows a user to perform system administration tasks
Programmer name: Michael A. Gregor
Course: COSC 146
Lab#: 7
Due Date: 3/10/16
lab7.pl
HEAD
print $heading;
my %passwords = (tom => "BigApple");
my %types = (tom => "admin");
my $menu = <<MENU;
System Administration Tasks
1- Create a new account
2- Delete an account
3- Change an account password
4- List users in alphabetical order
5- Exit the system
MENU
while (print $menu)
{
my $choice = prompt4input ("Make your choice: ");
if ($choice == 1) {createAccount(); next;}
if ($choice == 2) {deleteAccount(); next;}
if ($choice == 3) {changePassword(); next;}
if ($choice == 4) {listUsers(); next;}
if ($choice == 5) {print "Good-bye!";exit(0);}
if ($choice == 6) {print Dumper (\%passwords);
print Dumper (\%types); next;}
print ("Bad Choice...Try Again!\n");
}
sub prompt4input #returns response to a prompt string
{
my $prompt = shift;
print $prompt;
my $input = <STDIN>;
$input =~ s/^\s*//; #remove leading whitespace
$input =~ s/\s*$//; #remove trailing whitespace
return $input;
}
sub createAccount
{
print "Creating Account...\n";
my $userID = prompt4input ("Enter your userID: ");
my $password = prompt4input ("Enter your password: ");
if (exists $passwords{$userID})
{
print "Error: Duplicate user id: $userID ";
return; #### update added
}
my $account_type;
while ($account_type = prompt4input(
"Enter the account type, admin (or regular): "),
$account_type !~ /admin|regular/)
{
$passwords{$userID} = $password;
$types{$userID} = $account_type;
}
print "Account for \'$userID\' was successfully created \n";
}
sub deleteAccount
{
my $userID = prompt4input ("Enter your userID: ");
my $password = prompt4input ("Enter your password: ");
if ($passwords{$userID} != "$password")
{
print "invalid user id/password combination!\n";
return;
}
if ($types{$userID} != "admin")
{
print "$userID is not an admin...can not delete!\n";
return;
}
delete $passwords{$userID};
delete $types{$userID};
}
sub changePassword
{
my $userID = prompt4input ("Enter your userID: ");
my $password = prompt4input ("Enter your password: ");
if ($passwords{$userID} != "$password")
{
print "invalid user id/password combination!\n";
return;
}
my $newPassword = prompt4input ("Enter new password: ");
$passwords{$userID} = $newPassword;
}
sub listUsers
{
# sort the users in descending order
my $counter = 1;
for my $userID (reverse sort keys %passwords)
{
print "$userID\t";
print "\n" if $counter++ % 3 == 0; #divisible by 3 evenly
}
print "\n";
}
| [reply] [d/l] |
Re: How do you sort keys of a hash in descending order and print 3 per line?
by Anonymous Monk on Mar 16, 2016 at 00:58 UTC
|
Below is my entire script, the problem I have is with Choice number 4.
ok, copy/paste your program, delete everything except "choice 4" and whats needed to run that portion, it shouldn't take long, and then your question code will be less than 20 lines
Also, you have too much copy/paste, you need more subroutines
| [reply] |
|
| [reply] |
|
Hi MikeyG,
I don't think the anonymonk was suggesting to edit your OP. For one thing, it's better to leave them alone for history (ie other posts may refer to text that is then removed...), and for another, it was useful to see your whole script. Also, you introduced a syntax error when cutting code out, so what's left no longer compiles, as your original script did.
I think the anonymonk was suggesting to create a Short, Self-Contained, Compilable Example, which eliminates all but the essential code to show your problem. Mind you it should compile and run. In your case you could have shown code with just your sub for question number 4, providing the test data in a hash. Then the monks would have only had a dozen lines of code to review, and you would get help more easily. (Edit: much as in the example bangor showed you.)
As an added bonus, creating a SSCCE is very closely related to debugging and often the process of doing it will lead you to the answer yourself.
The way forward always starts with a minimal test.
| [reply] |
|
|