Long Dao Long Dao - 1 month ago 7
Android Question

Regex for at least 3 (numbers and special characters) in Android

I have a password rule that needs to satisfy those condition below:

At least 2 out of the following:
- At least 1 lowercase character
- At least 1 uppercase character
- At least 2 (numbers AND special characters)

I build my regex like this below:

String oneLowercaseCharacter = ".*[a-z].*";
String oneUppercaseCharacter = ".*[A-Z].*";
String oneNumber = ".*\\d.*";
String oneSpecialCharacter = ".*[^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*";
String threeNumbersAndCharacters = ".*[0-9\\^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*[0-9\\^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*[0-9\\^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*";


And then I build the function like this below:

if ((Pattern.compile(oneLowercaseCharacter).matcher(s).find() && Pattern.compile(oneUppercaseCharacter).matcher(s).find())
|| (Pattern.compile(oneLowercaseCharacter).matcher(s).find()
&& Pattern.compile(oneSpecialCharacter).matcher(s).find()
&& Pattern.compile(oneNumber).matcher(s).find()
&& Pattern.compile(threeNumbersAndCharacters).matcher(s).find())
|| (Pattern.compile(oneUppercaseCharacter).matcher(s).find()
&& Pattern.compile(oneSpecialCharacter).matcher(s).find()
&& Pattern.compile(oneNumber).matcher(s).find()
&& Pattern.compile(threeNumbersAndCharacters).matcher(s).find())) {
//Do my stuff here
}


However, it does not work as expected. Not really sure why but if I test with different passwords, results show like this:

qwerty123 true (not expected)

qwerty!@# false

qwerty12. true

Qwerty123 true

Qwerty12. true

Anyone has any idea where I missed?

Note: I search around stackoverflow already and look elsewhere already so that I came up with the above code, however could not go further.

Answer

The problem is in this line:

String oneSpecialCharacter = ".*[^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*";

The character ^ has a special meaning ("not") when it is used in the first position inside [].

This is why you need to escape it.

String oneSpecialCharacter = ".*[\\^\\`\\~\\<\\,\\>\\\"\\'\\}\\{\\]\\[\\|\\)\\(\\;\\&\\*\\$\\%\\#\\@\\!\\:\\.\\/\\?\\\\\\+\\=\\-\\_\\ ].*";

Now your result should looks like this:

qwerty123 -> false
qwerty!@# -> false 
qwerty12. -> true
Qwerty123 -> true
Qwerty12. -> true