Suhas
Suhas

Reputation: 33

Valid Username without Regex

The Question is to check a valid username:

Conditions are:

1.The username consists of 8 to 30 characters inclusive. If the username consists of less than 8 or greater than 30 characters, then it is an invalid username.

2.The username can only contain alphanumeric characters and underscores (_). Alphanumeric characters describe the character set consisting of lowercase characters [a-z], uppercase characters [A-Z], and digits [0-9].

3.The first character of the username must be an alphabetic character, i.e., either lowercase character [a-z] or uppercase character [A-Z].

Sample Input:

8

Julia

Samantha

Samantha_21

1Samantha

Samantha?10_2A

JuliaZ007

Julia@007

_Julia007

Sample Output:

Invalid

Valid

Valid

Invalid

Invalid

Valid

Invalid

Invalid

I am getting wrong output to some cases.

For Input: JuliaZ007 , I should get Valid but getting Invalid. Remaining are correct.

Can I know what's wrong in the code.

https://www.hackerrank.com/challenges/valid-username-checker/problem?isFullScreen=false

import java.io.*;
import java.util.*;

public class Solution {
private static final Scanner scan = new Scanner(System.in);

public static void main(String[] args) {
    int flag=1;
    int n = Integer.parseInt(scan.nextLine());
    while (n-- != 0) {
        String userName = scan.nextLine();
        char a[] = userName.toCharArray();
        String specialCharactersString = "!@#$%&*()'+,-./:;<=>?[]^`{|}";
        for (int i=0;i<userName.length();i++)
        {
        char ch = userName.charAt(i);
        if(specialCharactersString.contains(Character.toString(ch)) && Character.isLetterOrDigit(ch)==false) 
        {
            flag=0;
        }
        }
        if (userName.length()>=8 && userName.length()<=30 && Character.isLetter(a[0])==true && flag==1)                   {
            System.out.println("Valid");
        } else {
            System.out.println("InValid");
        }           
    }
}

}

Upvotes: 2

Views: 2778

Answers (4)

Dave Lee
Dave Lee

Reputation: 516

Not the best solution but you can simply update the range of number of characters. Here's an example of regex.

/^(?=.{6,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$/

Upvotes: 0

Abra
Abra

Reputation: 20914

Note that methods in class java.lang.Character, such as isLetterOrDigit, will check for characters (or digits) in any language.

Since your question stipulates that the digits must be those commonly referred to as arabic numerals and the letters must be those in the English alphabet, the below code uses the unicode code points of each character in the user-entered userName.

import java.util.Scanner;

public class Solution {
    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        String result;
        int n = Integer.parseInt(scan.nextLine());
        while (n-- != 0) {
            result = "invalid";
            String userName = scan.nextLine();
            int len = userName.length();
            if (len >= 8  &&  len <= 30) {
                char[] letters = userName.toCharArray();
                if ((letters[0] >= 65  &&  letters[0] <= 90)  ||  (letters[0] >= 97  &&  letters[0] <= 122)) {
                    int i = 1;
                    for (; i < len; i++) {
                        if ((letters[i] >= 48  &&  letters[i] <= 57)  ||
                            (letters[i] >= 65  &&  letters[i] <= 90)  ||
                            (letters[i] >= 97  &&  letters[0] <= 122) ||
                            (letters[i] == 95)) {
                            continue;
                        }
                        break;
                    }
                    if (i == len) {
                        result = "valid";
                    }
                }
            }
            System.out.println(result);
        }
    }
}

Edit

Just for the sake of it, here is a solution that uses the stream API.

import java.util.Scanner;

public class Solution {
    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        String result;
        int n = Integer.parseInt(scan.nextLine());
        while (n-- != 0) {
            result = "invalid";
            String userName = scan.nextLine();
            int len = userName.length();
            if (len >= 8  &&  len <= 30) {
                char letter = userName.charAt(0);
                if ((letter >= 65 && letter <= 90) || (letter >= 97 && letter <= 122)) {
                    if (userName.chars()
                                .skip(1L)
                                .allMatch(c -> (c >= 48  &&  c <= 57)  || // c is a digit
                                               (c >= 65  &&  c <= 90)  || // c is uppercase letter
                                               (c >= 97  &&  c <= 122) || // c is lowercase letter
                                               (c == 95))) { // c is underscore
                        result = "valid";
                    }
                }
            }
            System.out.println(result);
        }
    }
}

Upvotes: 0

ThrowsError
ThrowsError

Reputation: 1689

With Regex

In your case regular expression is most appropriate:

import java.util.Scanner;
import java.util.regex.Pattern;

public class Solution {
    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        final String regex = "^[a-zA-Z][\\w_]{7,29}$";
        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);

        int n = Integer.parseInt(scan.nextLine());
        while (n-- != 0) {
            String userName = scan.nextLine();
            if (pattern.matcher(userName).matches())
                System.out.println("Valid");
            else
                System.out.println("InValid");
        }
    }

}

Without Regex

import java.util.Scanner;

public class Solution {
    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        int n = Integer.parseInt(scan.nextLine());
        while (n-- != 0) {
            String userName = scan.nextLine();
            if (isValid(userName))
                System.out.println("Valid");
            else
                System.out.println("InValid");
        }
    }

    public static boolean isValid(String userName) {
        if (!Character.isAlphabetic(userName.charAt(0))
                || userName.length() < 8
                || userName.length() > 30)
            return false;
        for (char c : userName.toCharArray()) {
            if (!Character.isLetterOrDigit(c) && c != '_')
                return false;
        }
        return true;
    }
}

Explain what causes the problem in the program

Your problem is caused by the flag.

Before JuliaZ007, you have the name Samantha?10_2A, but this name sets the flag to 0. And when you are in the JuliaZ007, the flag is always 0 and you get a InValid.

To correct this problem, you can reset flag to 1 on each new name. For this, you can simply move the int flag = 1 in the while.

Example :

import java.io.*;
import java.util.*;

public class Solution {
    private static final Scanner scan = new Scanner(System.in);

    public static void main(String[] args) {
        int n = Integer.parseInt(scan.nextLine());
        while (n-- != 0) {
            int flag = 1;
            String userName = scan.nextLine();
            char a[] = userName.toCharArray();
            String specialCharactersString = "!@#$%&*()'+,-./:;<=>?[]^`{|}";
            for (int i = 0; i < userName.length(); i++) {
                char ch = userName.charAt(i);
                if (specialCharactersString.contains(Character.toString(ch))
                        && Character.isLetterOrDigit(ch) == false) {
                    flag = 0;
                }
            }
            if (userName.length() >= 8 && userName.length() <= 30 && Character.isLetter(a[0]) == true && flag == 1) {
                System.out.println("Valid");
            } else {
                System.out.println("InValid");
            }
        }
    }

}

Upvotes: 1

hfontanez
hfontanez

Reputation: 6168

The username consists of 8 to 30 characters inclusive. If the username consists of less than 8 or greater than 30 characters, then it is an invalid username.

boolean valid = true;
if (userName.length() < 8 || userName.length() > 30) { 
    valid = false;
}

The username can only contain alphanumeric characters and underscores

if (valid) {
    for (int  i = 0; i < userName.length(); i++) {
        boolean temp = c
        Character c = userName.charAt(i);
        valid = Character.isLetterOrDigit(c);
        // before invalidating, check to see if it is an underscore
        if (!valid) {
            valid = c == '_';
            if (!valid)
                break;
        }
    }
}

The first character of the username must be an alphabetic character

if (valid) {
    valid = Character.isLetter(userName.charAt(0));
}

Once you execute all validation steps, simply return valid;. On a side note, you can check the rule of the first character while looping to check the validity of the remaining character. I just did separate checks for clarity and for separating all three requirements for validation.

LASTLY, I want to point out this is most likely NOT the most optimal solution for non-regex. However, I broke it down in these steps because I feel strongly that as a beginner developer, you should attack problems in this manner: first break down the problem into individual, smaller problems. Then, come up to the solution of each independently, and lastly, integrate the smaller solutions into the final product.

Upvotes: 0

Related Questions