Reputation: 199
After trying other variations, I use this regular expression in Java to validate a password:
PatternCompiler compiler = new Perl5Compiler();
PatternMatcher matcher = new Perl5Matcher();
pattern = compiler.compile("^(?=.*?[a-zA-Z])(?![\\\\\\\\_\-])(?=.*?[0-9])([A-Za-z0-9-/-~]
[^\\\\\\\\_\-]*)$");
But it still doesn't match my test cases as expected:
Apr@2017
match
$$Apr@2017
no match, but it should match
!!Apr@2017
no match, but it should match
!#ap#2017
no match, but it should match
-Apr@2017
it should not match
_Apr@2017
it should not match
\Apr@2017
it should not match
Except three special characters -
_
\
remaining, all should match at the start of the string.
Rules:
It should accept all special characters any number of times except above three symbols.
It must and should contain one number and Capital letter at any place in the string.
Upvotes: 0
Views: 1676
Reputation: 627607
You seem to need
"^(?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9])[^\\\\_-]*$"
See the regex demo
^
- start of string(?=[^a-zA-Z]*[a-zA-Z])
- a positive lookahead that requires at least 1 ASCII letter ([a-zA-Z]
) to appear after 0+ chars other than letters ([^a-zA-Z]*
)(?=[^0-9]*[0-9])
- at least 1 ASCII digit (same principle of contrast as above is used here)[^\\\\_-]*
- 0+ chars other than \
(inside a Java string literal, \
should be doubled to denote 1 literal backslash, and to match a single backslash with a regex, we need double literal backslash), _
, -
$
- end of string (\\z
might be better though as it matches at the very end of the string).Upvotes: 0
Reputation: 8342
Here's an alternative solution - reverse the condition. This regex
^(?:[^0-9]*|[^A-Z]*|[_\\-].*)$
matches non conforming passwords. This makes it much simpler to understand.
It matches either
_
, \
or -
See it illustrated here at regex101.
There are some unclear issues remaining in your question though, so it may have to be adjusted. (The restriction in starting character I mentioned as a comment)
Upvotes: 0
Reputation: 86701
You have two rules, why not create more than one regular expression?
It should accept all special characters any number of times except above three symbols.
For this one, make sure it does not match [-\\_]
(note that the -
is the first character in the character class or it will be interpreted as a range.
It must and should contain one number and Capital letter at any place in the string.
For this one, make sure it matches [A-Z]
and [0-9]
To make it easy to modify and extend, do some abstraction:
class PasswordRule
{
private Pattern pattern;
// If true, string must match, if false string must not match
private boolean shouldMatch;
PasswordRule(String patternString, boolean shouldMatch)
{
this.shouldMatch = shouldMatch;
this.pattern = compiler.compile(patternString);
}
boolean match(String passwordString)
{
return pattern.matches(passwordString) == shouldMatch;
}
}
I don't know or care if I have the API to Perl5 matching correct in the above, but you should get the idea. Then your rules go in an array
PasswordRule rules[] =
{
PasswordRule("[-\\\\_]", false),
PasswordRule("[A-Z]", true),
PasswordRule("[0-9]", true)
};
boolean passwordIsOk(String password)
{
for (PasswordRule rule : rules)
{
if (!rule.match(password)
{
return false;
}
}
return true;
}
Using the above, your rules are far more flexible and modifiable than one monstrous regular expression.
Upvotes: 1