Hi. I am new to Java and am trying to figure out a homework problem. It is a password verifier with the following criteria:

  • at least 6 characters long
  • conatin at least one uppercase and one lowercase letter
  • should have at least one digit

This is what I have so far - but am not sure how to loop from letter to letter in the user's input.

import java.util.Scanner;

public class PasswordDemo
{
        public static void main(String[] args)
        {
                String input;  // To hold input

                // Create a Scanner object for keyboard input.
                Scanner keyboard = new Scanner(System.in);

                // Get a password.
                System.out.print("Enter a password: ");
                input = keyboard.nextLine();

                // Check the password.
                if (!PasswordVerifier.isValid(input))
                        System.out.println("Invalid password.");
                else
                        System.out.println("Valid password.");
        }
}


import java.util.Scanner;

class PasswordVerifier
{
	static String str;
	
	public static isValid(String str)
	{
		//I am not sure what to put here so that this method works right to return the value to the main method.
		
	}
	
	private static boolean hasLength(String str)
	{
	boolean goodSoFar = true;
	
	if (str.length() >=6)
		goodSoFar = false;
		System.out.println("The password is not long enough.  Try again.");
	return goodSoFar;
	}
	
	 private static boolean hasUpperCase(String str)
	 {
		 boolean goodSoFar = true;
		 int i = 0;
		 
		 while (goodSoFar && i < 6)
		 {
			 if (!Character.isUpperCase(str.charAt(i)))
				 goodSoFar = false;
			 	System.out.println("The password must have at least one UpperCase letter.  Try again.");
			 i++;
		 }
		 
		 return goodSoFar;
	 }
	   
	 private static boolean hasLowerCase(String str)
	 {
		boolean goodSoFar = true;
		int i = 0;
		
		while (goodSoFar && i < 6)
		{
			if (!Character.isLowerCase(str.charAt(i)))
				goodSoFar = false;
				System.out.println("The password must have at least one lower case letter.  Try again.");
			i++;
		}
		
		return goodSoFar;
	 }
	   
	 private static boolean hasDigit(String str)
	 {
		 boolean goodSoFar = true;
		 int i = 0;
		 
		 while (goodSoFar && i < 6)
		 {
			 if (!Character.isDigit(str.charAt(i)))
				 goodSoFar = false;
			 	System.out.println("The password must contain at least one number.  Try again.");
			 i++;
		 }
		 
		 return goodSoFar;
	 }


}

Any help would be appreciated.

Isn't your loop on

str.charAt(i)

looping through on each character in the input string?

Also, I think you want to loop from 0 to the length of the input string, not 0-6. The characters for which you are checking don't have to be in the first 6 characters of a longer password.

Also, better logic would be to start off the verification functions with a boolean, "good," set equal to false and then switch it to true and return when you find the special characters you are looking for.

i.e. :

good = false;
for( int i = 0 through inputLength)
{
if( inputString == specialChar)
{
set good = true
return good
}
}

Edited 7 Years Ago by donaldw: n/a

Comments
donaldw is very helpful. I couldn't have figured out this problem without the help! Thanks!

Isn't your loop on

str.charAt(i)

looping through on each character in the input string?

Also, I think you want to loop from 0 to the length of the input string, not 0-6. The characters for which you are checking don't have to be in the first 6 characters of a longer password.

Also, better logic would be to start off the verification functions with a boolean, "good," set equal to false and then switch it to true and return when you find the special characters you are looking for.

i.e. :

good = false;
for( int i = 0 through inputLength)
{
if( inputString == specialChar)
{
set good = true
return good
}
}

You are right. I totally forgot to put str.length() instead of 6 - of course the password can be longer than 6 - it just has to be at least 6 characters. Thanks for the catch.

so now that I have the password being verified - where should i return the goodSoFar? I need help getting isValid set up so it returns to the PasswordDemo - any suggestions on where to start?

Well, if you've got, say, three functions, gotLength(...), gotUpper(...) and gotDigit(...), each of which returns a boolean TRUE if the password meets the requirements and FALSE if it's not a valid password you could verify it from your main program as follows:

if( gotLength(...) && gotUpper(...) && gotDigit(...) )
// password is good, act accordingly
else
// password is not good, act accordingly
Comments
again, genius....this guy is the best!

Here is my code again. I still have something wrong because no matter what I put I get that the password is valid.

import java.util.Scanner;

public class PasswordDemo
{
        public static void main(String[] args)
        {
                String input;  // To hold input

                // Create a Scanner object for keyboard input.
                Scanner keyboard = new Scanner(System.in);

                // Get a password.
                System.out.print("Enter a password: ");
                input = keyboard.nextLine();

                // Check the password.
                if (!PasswordVerifier.hasLength(input) && !PasswordVerifier.hasUpperCase(input) &&
                		!PasswordVerifier.hasLowerCase(input) && !PasswordVerifier.hasDigit(input))
                        System.out.println("Invalid password.");
                else
                        System.out.println("Valid password.");
        }
}


class PasswordVerifier
{
	static String str;
	
	
	static boolean hasLength(String str)
	{
	boolean goodSoFar = false;
	
	if (str.length() >=6)
		goodSoFar = true;
	return goodSoFar;
	}
	
	 static boolean hasUpperCase(String str)
	 {
		 boolean goodSoFar = false;
		 int i = 0;
		 
		 while (goodSoFar && i < str.length())
		 {
			 if (!Character.isUpperCase(str.charAt(i)))
				 goodSoFar = true;
			 i++;
		 }
		 
		 return goodSoFar;
	 }
	   
	 static boolean hasLowerCase(String str)
	 {
		boolean goodSoFar = false;
		int i = 0;
		
		while (goodSoFar && i < str.length())
		{
			if (!Character.isLowerCase(str.charAt(i)))
				goodSoFar = true;
			i++;
		}
		
		return goodSoFar;
	 }
	   
	 static boolean hasDigit(String str)
	 {
		 boolean goodSoFar = false;
		 int i = 0;
		 
		 while (goodSoFar && i < str.length())
		 {
			 if (!Character.isDigit(str.charAt(i)))
				 goodSoFar = true;
			 i++;
		 }
		 
		 return goodSoFar;
	 }


}

I think my logic is still off a little - it may be that my head is pounding at this point. :) I know that I am close though. You have been so helpful! Thanks for all of your help!

Comments
Good to see someone doing the work and learning rather than just asking for an answer.
if (!PasswordVerifier.hasLength(input) &&!PasswordVerifier.hasUpperCase(input) &&!PasswordVerifier.hasLowerCase(input) &&!PasswordVerifier.hasDigit(input))
System.out.println("Invalid password.");
else
System.out.println("Valid password.");

With this code, input would have to fail ALL tests to be considered invalid. You want it to be invalid if it fails ANY test.

Edited 7 Years Ago by donaldw: n/a

more problems here:

static boolean hasUpperCase(String str)
	 {
		 boolean goodSoFar = false;
		 int i = 0;
		 while (goodSoFar && i < str.length())
		 {
			 if (!Character.isUpperCase(str.charAt(i)))
				 goodSoFar = true;
			 i++;
		 }
		 return goodSoFar;
	 }

Think about what you're doing here. goodSoFar is being set to false, then you have a loop condition that requires it to be true to execute. Will the code inside of your while loop ever execute?

Also, your if statement says to set goodSoFar to true if each character is NOT an uppercase character. I think that if

Character.isUpperCase(str.charAt(i))

is true, then you've met the upper case character requirements, you can set your goodSoFar value to true and stop inspecting the input for this requirement. Check for the same logic error in your other functions as well.

So I came to the realization that I am making this way more complicated than it needs to be. Here is my new and improved code:

import java.util.Scanner;

/*
 * This program is to demonstrate the password verifier class.
 */
public class PasswordDemo
{
        public static void main(String[] args)
        {
                String input;  // To hold input

                // Create a Scanner object for keyboard input.
                Scanner keyboard = new Scanner(System.in);

                // Get a password.
                System.out.print("Enter a password: ");
                input = keyboard.nextLine();

                // Check the password.
                if (PasswordVerifier.isValid(input))
                        System.out.println("Valid password.");
                else
                        System.out.println("InValid password.");
        }
}


class PasswordVerifier
{
	static String str;
	
	
	static boolean isValid(String str)
	{
		boolean goodSoFar = true;
		int i = 0;
		
		if (str.length() < 6)
			goodSoFar = false;
		
		if(Character.isUpperCase(str.charAt(i)))
			goodSoFar = true;
		else if(!Character.isUpperCase(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		if(Character.isLowerCase(str.charAt(i)))
			goodSoFar = true;
		else if(!Character.isLowerCase(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		if(Character.isDigit(str.charAt(i)))
			goodSoFar = true;
		else if (!Character.isDigit(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		return goodSoFar;
			
	}
}

I started with just the length and ran the program and it worked. Then I added the is.UpperCase and it worked correctly.
Then the is.LowerCase and it worked correctly.

BUT - for some reason my is.Digit is not working correctly. Do you see what I might have done wrong?

Thanks! I am really close - I can feel it!!!

static boolean isValid(String str)
	{
		boolean goodSoFar = true;
		int i = 0;
		
		if (str.length() < 6)
			goodSoFar = false;
		
		if(Character.isUpperCase(str.charAt(i)))
			goodSoFar = true;
		else if(!Character.isUpperCase(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		if(Character.isLowerCase(str.charAt(i)))
			goodSoFar = true;
		else if(!Character.isLowerCase(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		if(Character.isDigit(str.charAt(i)))
			goodSoFar = true;
		else if (!Character.isDigit(str.charAt(i)))
			goodSoFar = false;
		i++;
		
		return goodSoFar;
}
}

Alright, looks like you're getting on a roll now, but your logic still isn't quite there. You are right though, you were making it more complicated that what it needed to be. The problem isn't your isDigit section, it's the logic of the whole function. Think about what it's doing:

- check length
- check if character is upper case (hint: i=0 here)
- increment i
- check if character is lower case (hint: i=1 here)
- increment i
- check if character is a digit (hint: i=2 here)
- increment i
- return your boolean

You're not checking the whole input string. I think you were on the right track with the while loops, although I would have used for loops.

What you want to do is to search the whole string (for character i=0 through i=length) to see if it's got an upper case character. If not, return false (it's not valid). If it does have an upper case character, continue on to the next check...Check each character in the input for lower case and use the same behavior as described above for the upper case situation. Once you find a good character for the test in question you can use a break statement to break out of the for (or while) loops.

Another way to do it would be to have a boolean value for each test (hasUpper, hasLower, hasDigit, hasLength) initialized to false, perform each test for the entire string, character by character, in a loop (setting the appropriate boolean variable true if you find a character which satisfies the test conditions). After you've performed all four tests, the booleans for the conditions which have been satisfied will be TRUE and those for conditions not met will be FALSE. Since all conditions must be met to be valid, you can

return (hasUpper && hasLower && hasDigit && hasLength);

which means that for the return value to be TRUE, all four of the arguments there need to be TRUE.

My mind wandered a bit while typing that. If it's not clear, let me know and I'll try to clarify.

You are being so patient with me. I really appreciate it!

is this any closer? I changed to a for loop - but I must not have it right still.

for (i = 0; i < str.length(); i++)
		{
			if(Character.isUpperCase(str.charAt(i)))
				goodSoFar = true;
			else goodSoFar = false;
			i++;
		}

So, if I get the for loop correct it should loop through the entire password before it moves on to the next for loop - and does the same thing, etc, etc. lol, I am not sure my brain is cut out for this!

Edited 7 Years Ago by smachee: correction to code.

for (i = 0; i < str.length(); i++)
		{
			if(Character.isUpperCase(str.charAt(i)))
				goodSoFar = true;
			else goodSoFar = false;
			i++;  // PS:  you don't need to increment i manually
                  // the for loop does it for you.  that's what the 3rd argument is.
		}

Your loop logic looks good with respect to setting the boolean TRUE/FALSE in the right places, but I would rethink how you're doing your logic and what you do when you pass or fail a test. The above is your code, I would change it to something more like:

for (i = 0; i < str.length(); i++)  // for each character in the input string
{
	// check the validity condition:
	if(Character.isUpperCase(str.charAt(i)))  // if this validity condition is met, 
		break;  // break out of this for loop, continue execution below
	else // if you get here, then the validity condition has failed
		return false; // so you can return FALSE
}

// if you get to this point in the execution, you passed the first validity condition (this is where "break" will put you).

// put in similar for loops for the remaining validity condition tests

Patience is a virtue. Admittedly, I'm sort of dragging it out and it seems to be working in that it looks like you're actually figuring it out on your own and learning from mistakes. I taught a college Java lab for 2.5 years and tried to do the same then. Old habits die hard.

Ok, I think I am a little confused again.

If true
it breaks to the next section
else
return false

But we don't want it to return false until it has a chance to check all of the letters...right? Or am I misunderstanding?

p.s. - this is the best way to learn so keep on spoon feeding me - lol, I am not above it! I am trying hard - I promise!

But we don't want it to return false until it has a chance to check all of the letters...right? Or am I misunderstanding?

D'OH! Very good, grasshopper. That was just....uh...a test! You passed :D


I don't know why that made sense to me when I was writing it. I gotta hit the shower and get ready for bed, so the easiest way I could think of would be the solution I suggested earlier with a BOOL for each test condition. That would look something more like:

bool hasLen = FALSE;
bool hasDigit = FALSE;
bool hasUppper = FALSE;
bool hasLower = FALSE;

for (i = 0; i < str.length(); i++)  // for each character in the input string
{
	// check the validity condition:
	if(Character.isUpperCase(str.charAt(i)))  // if this validity condition is met, 
        {
		hasUpper = TRUE;
		break;  //not really necessary I suppose since hasUpper can't turn back to FALSE, but it might save you a few nanoseconds of computation
        }
// you don't really need to do anything if the condition isn't met, the bool is initialized to FALSE
}

// you can either check the hasUpper bool and return FALSE if it is FALSE or you can perform the rest of the checks and:

return (hasLen && hasUpper && hasLower && hasDigit);

I'll try to check the thread again before I turn in. Hopefully you stick around and hang out with the "community" even after you finish this assignment.

Gosh, I am not sure I can switch gears like that - what is easy for you is still hard for me. :icon_neutral:

I will give it a shot tomorrow! Thanks for the help today!

Gosh, I am not sure I can switch gears like that - what is easy for you is still hard for me. :icon_neutral:

I will give it a shot tomorrow! Thanks for the help today!

No sweat. FWIW, it's not really switching gears too much though. It might be simpler if explained this way:

To be valid, a password must meet four criteria: length must be greater than 6, must contain at least one upper case letter, must contain at least one lower case letter and must contain at least one digit.

Your isValid(...) function must check each of these four conditions and return either TRUE (meaning that all four conditions have been met) or FALSE (meaning that one or more conditions have failed. It doesn't matter how many fail, if any fail, the whole thing fails). This latest thing I'm talking about just breaks it up into smaller, bite size chunks within your isValid function.

We should be in agreement that the four test must all pass, so we want to declare the four booleans, one for each test:

bool hasLen = FALSE;
bool hasDigit = FALSE;
bool hasUppper = FALSE;
bool hasLower = FALSE;

These just provide a way for the program to keep track of each test. They are being initialized to FALSE for convenience's sake.

We then perform each test, in any order, setting each test's boolean value to TRUE if it passes. The format of this will be (don't let the big code block intimidate you, it's mostly comments):

isValid(...)
{
if( inputIsLongEnough ) hasLen = true; // if it's long enough, set the bool accordingly

//when we get here, if the length was long enough, hasLen is TRUE.  If it failed that test, then no action was taken and hasLen remains the way it was initialized, FALSE

if( inputHasUpperCase ) hasUpper = true; // if it has any upper case letters, set the bool accordingly

//when we get here, if there were any upper case letters, hasUpper is TRUE.  If it failed that test, then no action was taken and hasUpper remains the way it was initialized, FALSE


if( inputHasLowerCase ) hasLower = true; // if it has any lower case letters, set the bool accordingly

//when we get here, if there were any upper case letters, hasLower is TRUE.  If it failed that test, then no action was taken and hasLower remains the way it was initialized, FALSE



if( inputHasDigit ) hasDigit = true; // if it has any digits, set the bool accordingly

//when we get here, if there were any numbers, hasDigit is TRUE.  If it failed that test, then no action was taken and hasDigit remains the way it was initialized, FALSE

return (hasLen && hasUpper && hasLower && hasDigit);  // this logical operator means to return the AND value of these four booleans.  If ALL FOUR boolean variables are TRUE (i.e. it passed all tests), then the return value will be TRUE.  If any one of them is false (i.e it failed one or more tests, we don't care how many), the return value will be FALSE.
}

Now, note that the lines that say

if( inputHasDigit ) hasDigit = true;

won't necessarily be that actual code and they don't even need to be function calls (which is how you initially did it in your OP). That is just whichever way you choose to do your test. You seemed to have a pretty good grasp of doing it with for loops, so that line would likely be replaced with something like

for (i = 0; i < str.length(); i++) 
{
	if(Character.isUpperCase(str.charAt(i)))
        {
		hasUpper = TRUE;
        }
}

So what you end up with is a fairly simple isValid function that consits of four boolean variables, one length comparison (which will manipulate one of the booleans) and three for loops to check for the presence of certain characters (each of which will manipulate one of the booleans). The function will then return the results of AND-ing the four booleans together. It may sound complicated, but you've got all the pieces and each of them is simple; it's just a matter of putting them together. The end result isn't all that complicated either.

Viel Gl├╝ck!

Brilliant! Thank you so much. I followed your advice and kept my for loops but changed to: hasLength, hasUpper, hasLower and hasDigit as the boolean. I then returned all four values and viola! It works!

Awesome job stepping me through the problem! Thanks for all of your help! I really learned alot!

This question has already been answered. Start a new discussion instead.