Milen Markov
Milen Markov

Reputation: 111

How do I match non-word characters anywhere in the string?

This is a simple question, but please hear me out - A part of a homework assignment for Java has a password validator method. The requirements are simple - password must be between 6-10 characters, must be made only of digits or letters and has to have at least 2 digits in it to be valid. I made this with if statements and using regex, for some reason I cannot get the non-word character regex to match despite every online regex checker showing this should work and even the jetbrains plugin for regex check shows this should be valid. (I also understand this could be done with a one-liner and none of the if statements but this way is simpler for me.

Example input - MyPass123 should be valid, MyPass123# should match the non-word character and should return "Password must consist only of letters and digits" instead this never happens. I am a beginner in Java so it is most likely I am not doing something right even though it is such a simple problem. Thank you in advance!

Method code below:

public static void passswordCheck(String password)
    {
        if(password.length()<6 || password.length()>10)
        {
            System.out.printf("Password needs to be between 6 and 10 characters");
        }
        else if(password.matches("\\W")) \\This should match when input is MyPass123#
        {
            System.out.printf("Password must consist only of letters and digits");
        }
        else if(!password.matches("/(\\d).*(\\d)/"))
        {
            System.out.printf("Password needs to have at least 2 digits");
        }
        else
        {
            System.out.printf("Password is valid");
        }
    }

Upvotes: 4

Views: 1286

Answers (4)

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79075

Problems in your code:

  1. You have used \W (i.e. [^\w]) which matches non-word character but note that \w matches not only digits and alphabets but also _ which you do not need in the valid password. Therefore, you need to use \p{Alnum}. Alternatively, you can use [A-Za-z0-9]. Also, in order to consider the whole string, the quantifier + is required.
  2. The pattern, \d.*\d matches the string bounded by two digits which can be at any place (i.e. not just at the beginning and at the end) in the password and therefore, you need to match any place, not the whole string. You can understand it from this example. Thus, String#match will be able to match the whole string only when the digits are placed in the beginning and at the end. Therefore, you need to use Matcher#find instead of String#match. Note that you do not need parenthesis ( ) around \d in your regex pattern. The parenthesis ( ) is used to specify capturing group which you do not need for your requirement.

Given below is a demo code addressing all these issues:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        // Test strings
        String[] arr = { "abcdefghjk", "abc1def2gh", "Ab1Cd2EfGh", "Ab1CdEfGhI", "Ab1Cd2E3Gh", "Ab_ed2EFG3" };
        for (String s : arr) {
            System.out.println("Validating the password, " + s);
            passswordCheck(s);
        }
    }

    public static void passswordCheck(String password) {
        if (password.length() < 6 || password.length() > 10) {
            System.out.println("Password needs to be between 6 and 10 characters.\n");
        } else if (!password.matches("\\p{Alnum}+")) {
            System.out.println("Password must consist only of letters and digits.\n");
        } else {
            Pattern pattern = Pattern.compile("\\d.*\\d");
            Matcher matcher = pattern.matcher(password);
            if (!matcher.find()) {
                System.out.println("Password needs to have at least 2 digits.\n");
            } else {
                System.out.println("Password is valid\n");
            }
        }
    }
}

Output:

Validating the password, abcdefghjk
Password needs to have at least 2 digits.

Validating the password, abc1def2gh
Password is valid

Validating the password, Ab1Cd2EfGh
Password is valid

Validating the password, Ab1CdEfGhI
Password needs to have at least 2 digits.

Validating the password, Ab1Cd2E3Gh
Password is valid

Validating the password, Ab_ed2EFG3
Password must consist only of letters and digits.

Upvotes: 0

rootkonda
rootkonda

Reputation: 1743

I have tested the below code. Two options are possible, try using the find method as mentioned by Konrad in one of the comments above or handle it in the regex to match a character anywhere in the string.

\\w{6,10} - Matches only the valid passwords which contains word character(A-Za-z0-9)

.*?\\d{2,}.*? - Looks for 2 or more consecutive digits

I have changed it to use Pattern.matches.

import java.util.regex.*;
public class test {
    public static void passswordCheck(String password)
    {
        if(password.length()<6 || password.length()>10)
        {
            System.out.println("Password needs to be between 6 and 10 characters");
        }
        else if(!Pattern.matches("\\w{6,10}",password)) //This should match when input is MyPass123#
        {
            System.out.println("Password must consist only of letters and digits");
        }
        else if(!Pattern.matches(".*?\\d{2,}.*?",password))
        {
            System.out.println("Password needs to have at least 2 digits");
        }
        else
        {
            System.out.println("Password is valid");
        }
    }
    public static void main(String[] args) 
    {
        passswordCheck("Mypass2");
    }
}

Upvotes: 1

Konrad Rudolph
Konrad Rudolph

Reputation: 545588

String#matches always performs a whole match, i.e. the match needs to span the whole string from the first to the last character. To search for a match anywhere in the string, you need to use the find method of a Matcher object instead:

final Pattern nonWordChar = Pattern.compile("\\W");
if (nonWordChar.matcher(password).find()) {
    System.out.printf("Password must consist only of letters and digits");
}
…

You will need to do the same with your other regular expressions.

Upvotes: 2

tpschmidt
tpschmidt

Reputation: 2707

You're only matching if the string consists of a single character which is non alphanumeric (= [^a-zA-Z0-9_]).

If you want any string which contains at least one non alphanumeric character: .*?\W.*

Upvotes: 2

Related Questions