I have a requirement for password rules. Following are the rules.
The password must follow the following guidelines:
Here's how I would do it:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ValidatePassword
{
public static void main (String[] args)
{
String pw = "abaslkA3FLKJ";
// create an array with 4 regex patterns
Pattern [] patternArray = {
Pattern.compile("[a-z]"),
Pattern.compile("[A-Z]"),
Pattern.compile("[0-9]"),
Pattern.compile("[&%$#]")
};
int matchCount = 0;
// iterate over the patterns looking for matches
for (Pattern thisPattern : patternArray) {
Matcher theMatcher = thisPattern.matcher(pw);
if (theMatcher.find()) {
matchCount ++;
}
}
if (matchCount >= 3) {
System.out.println("Success");
}
else {
System.out.println("Failure: only " + matchCount + " matches");
}
}
}
I only added a few special characters to the 4th pattern... You'll have to modify it for your needs. You may need to escape certain characters with a backslash. You may also want to add other constraints like checking for no spaces. I'll leave that up to you.
This is, if you want an elegant regex, as close as you can get
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&'])[^ ]{8,}$
The basic idea is to use a technique called "positive lookahead" :
(?=.*PutHereWhatYouWantToAllow)
Your extra requirement 3 out of 4 is not easy to solve with regexes cause you cannot make them count basically. You could write out the necessary permutations of the above regex (tell me if it doesn't make sense) but that would make a very long regex. What you could do is write out the permutations in code so that the regex stays maintainable since you are not repeating the patterns literally.
I'll have a shot if I you tell me your language (C#?) cause it's a good challenge.
Update 1
Here is the regex that will match at least 3 of your requirements (4 is also allowed), just for the challenge of it. Don't use this in production but loop in the language with individual regexes as mentioned in the comments.
^((?=.[a-z].[A-Z].[\d])|(?=.[a-z].[\d].[A-Z])|(?=.[A-Z].[a-z].[\d])|(?=.[A-Z].[\d].[a-z])|(?=.[\d].[a-z].[A-Z])|(?=.[\d].[A-Z].[a-z])|(?=.[a-z].[A-Z].[!@#$%^&'])|(?=.[a-z].[!@#$%^&'].[A-Z])|(?=.[A-Z].[a-z].[!@#$%^&'])|(?=.[A-Z].[!@#$%^&'].[a-z])|(?=.[!@#$%^&'].[a-z].[A-Z])|(?=.[!@#$%^&'].[A-Z].[a-z])|(?=.[a-z].[\d].[!@#$%^&'])|(?=.[a-z].[!@#$%^&'].[\d])|(?=.[\d].[a-z].[!@#$%^&'])|(?=.[\d].[!@#$%^&'].[a-z])|(?=.[!@#$%^&'].[a-z].[\d])|(?=.[!@#$%^&'].[\d].[a-z])|(?=.[A-Z].[\d].[!@#$%^&'])|(?=.[A-Z].[!@#$%^&'].[\d])|(?=.[\d].[A-Z].[!@#$%^&'])|(?=.[\d].[!@#$%^&'].[A-Z])|(?=.[!@#$%^&'].[A-Z].[\d])|(?=.[!@#$%^&'].[\d].[A-Z]))[^ ]{8,}$
Update 2
This is the approach to take in java
From the comments I read that you are testing like the following
I don't think you are on the right track here. The lowercase will only report success if all characters are lowercase, and not just one. Same remark for the rest.
These are the 4 individual regexes of which at least 3 should report a match
[a-z]
[A-Z]
\d
[!@#$%^&']
Here is the test that the password should not contain a space
^[^ ]*$
The test for at least 8 characters
.{8,}
So I split the requirements and not combine them. This should make for more readable code especially if one starts with regexes.