Kiran
Kiran

Reputation: 199

Regular expression special characters not working at the starting of the string in java

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:

Upvotes: 0

Views: 1676

Answers (3)

Wiktor Stribiżew
Wiktor Stribiżew

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

SamWhan
SamWhan

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

  • a string free from digits
  • a string free from capital letters
  • a string containing either of _, \ 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

JeremyP
JeremyP

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

Related Questions