Checking letter case (Upper/Lower) within a string in Java

Java

Java Problem Overview


The problem that I am having is that I can't get my Password Verification Program to check a string to ensure that, 1 of the characters is in upper case and one is in lower case, it will check the whole string for one of the other and print the error message based on which statement it is checking.

I have looked over this site and the internet for an answer and I am unable to find one. This is homework.

Below is my current code.

import java.util.Scanner;

public class password
{
    public static void main(String[] args)
    {
        Scanner stdIn = new Scanner(System.in);
        String password;
        String cont = "y";
        char ch;
        boolean upper = false;
        boolean lower = false;

        System.out.println("Setting up your password is easy. To view requirements enter Help.");
        System.out.print("Enter password or help: ");
        password = stdIn.next();
        ch = password.charAt(0);

        while (cont.equalsIgnoreCase("y"))
        {
            while (password.isEmpty())
            {
                System.out.print("Enter password or help: ");
                password = stdIn.next();       
            }

            if (password.equalsIgnoreCase("help"))
            {
                 System.out.println("Password must meet these requirements." +
                     "\nMust contain 8 characters.\nMust contain 1 lower case letter." +
                     "\nMust contain 1 upper case letter.\nMust contain 1 numeric digit." +
                     "\nMust contain 1 special character !@#$%^&*\nDoes not contain the word AND or NOT.");

                password = "";
            }
            else if (password.length() < 8)
            {
                System.out.println("Invalid password - Must contain 8 charaters.");
                password = "";
            }
            else if (!(Character.isLowerCase(ch)))
            {
                for (int i=1; i<password.length(); i++)
                {
                    ch = password.charAt(i);

                    if (!Character.isLowerCase(ch))
                    {  
                        System.out.println("Invalid password - Must have a Lower Case character.");
                        password = "";
                    }
                }
            }
            else if (!(Character.isUpperCase(ch)))
            {
                for (int i=0; i<password.length(); i++)
                {       
                    ch = password.charAt(i);

                    if (!Character.isUpperCase(ch))
                    {
                        System.out.println("Invalid password - Must have an Upper Case character.");
                        password = "";
                    }
                }
            }
            else
            {
                System.out.println("Your password is " + password);

                System.out.print("Would you like to change your password? Y/N: ");
                cont = stdIn.next();
                password = "";
            }

            while (!cont.equalsIgnoreCase("y") && !cont.equalsIgnoreCase("n"))
            {
                System.out.print("Invalid Answer. Please enter Y or N: ");
                cont = stdIn.next();
            }
        }
    }
}

Java Solutions


Solution 1 - Java

To determine if a String contains an upper case and a lower case char, you can use the following:

boolean hasUppercase = !password.equals(password.toLowerCase());
boolean hasLowercase = !password.equals(password.toUpperCase());

This allows you to check:

if(!hasUppercase)System.out.println("Must have an uppercase Character");
if(!hasLowercase)System.out.println("Must have a lowercase Character");

Essentially, this works by checking if the String is equal to its entirely lowercase, or uppercase equivalent. If this is not true, then there must be at least one character that is uppercase or lowercase.

As for your other conditions, these can be satisfied in a similar way:

boolean isAtLeast8   = password.length() >= 8;//Checks for at least 8 characters
boolean hasSpecial   = !password.matches("[A-Za-z0-9 ]*");//Checks at least one char is not alpha numeric
boolean noConditions = !(password.contains("AND") || password.contains("NOT"));//Check that it doesn't contain AND or NOT

With suitable error messages as above.

Solution 2 - Java

A loop like this one:

else if (!(Character.isLowerCase(ch)))
            {
                for (int i=1; i<password.length(); i++)
                {
                   ch = password.charAt(i);

                    if (!Character.isLowerCase(ch))
                       {  
                        System.out.println("Invalid password - Must have a Lower Case character.");
                        password = "";
                       }
                     // end if
                } //end for
            }

Has an obvious logical flaw: You enter it if the first character is not lowercase, then test if the second character is not lower case. At that point you throw an error.

Instead, you should do something like this (not full code, just an example):

boolean hasLower = false, hasUpper = false, hasNumber = false, hasSpecial = false; // etc - all the rules
for ( ii = 0; ii < password.length(); ii++ ) {
  ch = password.charAt(ii);
  // check each rule in turn, with code like this:
  if Character.isLowerCase(ch) hasLower = true;
  if Character.isUpperCase(ch) hasUpper = true;
  // ... etc for all the tests you want to do
}

if(hasLower && hasUpper && ...) {
  // password is good
} 
else {
  // password is bad
}

Of course the code snippet you provided, besides the faulty logic, did not have code to test for the other conditions that your "help" option printed out. As was pointed out in one of the other answers, you could consider using regular expressions to help you speed up the process of finding each of these things. For example,

hasNumber  : use regex pattern "\d+" for "find at least one digit"
hasSpecial : use regex pattern "[!@#$%^&*]+" for "find at least one of these characters"

In code:

hasNumber  = password.matches(".*\\d.*");  // "a digit with anything before or after"
hasSpecial = password.matches(".*[!@#$%^&*].*");
hasNoNOT   = !password.matches(".*NOT.*");
hasNoAND   = !password.matches(".*AND.*");

It is possible to combine these things in clever ways - but especially when you are a novice regex user, it is much better to be a little bit "slow and tedious", and get code that works first time (plus you will be able to figure out what you did six months from now).

Solution 3 - Java

Although this code is likely beyond the understanding of a novice, it can be done in one line using a regex with positive and negative look-aheads:

boolean ok = 
    password.matches("^(?=.*[A-Z])(?=.*[!@#$%^&*])(?=.*\\d)(?!.*(AND|NOT)).*[a-z].*");

Solution 4 - Java

This is quite old and @SinkingPoint already gave a great answer above. Now, with functional idioms available in Java 8 we could give it one more twist. You would have two lambdas:

Function<String, Boolean> hasLowerCase = s -> s.chars().filter(c -> Character.isLowerCase(c)).count() > 0;
Function<String, Boolean> hasUpperCase = s -> s.chars().filter(c -> Character.isUpperCase(c)).count() > 0;

Then in code we could check password rules like this:

if (!hasUppercase.apply(password)) System.out.println("Must have an uppercase Character");
if (!hasLowercase.apply(password)) System.out.println("Must have a lowercase Character");

As to the other checks:

Function<String,Boolean> isAtLeast8 = s -> s.length() >= 8; //Checks for at least 8 characters
Function<String,Boolean> hasSpecial   = s -> !s.matches("[A-Za-z0-9 ]*");//Checks at least one char is not alpha numeric
Function<String,Boolean> noConditions = s -> !(s.contains("AND") || s.contains("NOT"));//Check that it doesn't contain AND or NOT

In some cases, it is arguable, whether creating the lambda adds value in terms of communicating intent, but the good thing about lambdas is that they are functional.

Solution 5 - Java

I have streamlined the answer of @Quirliom above into functions that can be used:

private static boolean hasLength(CharSequence data) {
    if (String.valueOf(data).length() >= 8) return true;
    else return false;
}

private static boolean hasSymbol(CharSequence data) {
    String password = String.valueOf(data);
    boolean hasSpecial = !password.matches("[A-Za-z0-9 ]*");
    return hasSpecial;
}

private static boolean hasUpperCase(CharSequence data) {
    String password = String.valueOf(data);
    boolean hasUppercase = !password.equals(password.toLowerCase());
    return hasUppercase;
}

private static boolean hasLowerCase(CharSequence data) {
    String password = String.valueOf(data);
    boolean hasLowercase = !password.equals(password.toUpperCase());
    return hasLowercase;
}

Solution 6 - Java

function TellFirstCharacterType(inputString){
    var firstCharacter = inputString[0];
    if(isNaN(firstCharacter)){
	    if(firstCharacter == firstCharacter.toUpperCase()){
		    return "It's a uppercase character";
	    }
	    else{
    	    return "It's a lowercase character";
	    }
    }
    else{
    	return "It's a Number";
    }
}

Solution 7 - Java

A quick look through the documentation on regular expression sytanx should bring up ways to tell if it contains a lower/upper case character at some point.

Solution 8 - Java

That's what I got:

    Scanner scanner = new Scanner(System.in);
    System.out.println("Please enter a nickname!");
    while (!scanner.hasNext("[a-zA-Z]{3,8}+")) {
        System.out.println("Nickname should contain only Alphabetic letters! At least 3 and max 8 letters");
        scanner.next();
    }
    String nickname = scanner.next();
    System.out.println("Thank you! Got " + nickname);

Read about regex Pattern here: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

Solution 9 - Java

package passwordValidator;

import java.util.Scanner;

public class Main {
	/**
	 * @author felipe mello.
	 */
	
	private static Scanner scanner = new Scanner(System.in);
	
	 /*
	 * Create a password validator(from an input string) via TDD
	 * The validator should return true if
	 * 	The Password is at least 8 characters long
	 * 	The Password contains uppercase Letters(atLeastOne)
	 *  The Password contains digits(at least one)
	 *  The Password contains symbols(at least one)
	 */

	
	public static void main(String[] args) {
		System.out.println("Please enter a password");
		String password = scanner.nextLine();	
		
		checkPassword(password);
	}
	/**
	 * 
	 * @param checkPassword the method check password is validating the input from the the user and check if it matches the password requirements
	 * @return
	 */
	public static boolean checkPassword(String password){
		boolean upperCase = !password.equals(password.toLowerCase()); //check if the input has a lower case letter
		boolean lowerCase = !password.equals(password.toUpperCase()); //check if the input has a CAPITAL case letter
		boolean isAtLeast8 = password.length()>=8; 					  //check if the input is greater than 8 characters
		boolean hasSpecial = !password.matches("[A-Za-z0-9]*");		  // check if the input has a special characters
		boolean hasNumber = !password.matches(".*\\d+.*"); 			  //check if the input contains a digit
		if(!isAtLeast8){
			System.out.println("Your Password is not big enough\n please enter a password with minimun of 8 characters");
			return true;
		}else if(!upperCase){
			System.out.println("Password must contain at least one UPPERCASE letter");
			return true;
		}else if(!lowerCase){
			System.out.println("Password must contain at least one lower case letter");
			return true;
		}else if(!hasSpecial){
			System.out.println("Password must contain a special character");
			return true;
		}else if(hasNumber){
			System.out.println("Password must contain at least one number");
			return true;
		}else{
			System.out.println("Your password: "+password+", sucessfully match the requirements");
			return true;
		}
		
	}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon AView Question on Stackoverflow
Solution 1 - JavaSinkingpointView Answer on Stackoverflow
Solution 2 - JavaFlorisView Answer on Stackoverflow
Solution 3 - JavaBohemianView Answer on Stackoverflow
Solution 4 - JavaCoffee_fanView Answer on Stackoverflow
Solution 5 - JavaUzairView Answer on Stackoverflow
Solution 6 - JavaRahul VaswaniView Answer on Stackoverflow
Solution 7 - JavaThomasView Answer on Stackoverflow
Solution 8 - JavaMikhailView Answer on Stackoverflow
Solution 9 - JavaFelipe MelloView Answer on Stackoverflow