2

I'm trying to create a RegExp to match new passwords (which works), but I only need a last step to make it work 100%.

Here's the RegExp and what it is supossed to:

((?=.*(\\d|[\\(\\)\\{\\}\\?!\\$&\\*%\\=\\+_\\-\\.]))(?=.*[a-z])(?=.*[A-Z]).{8,})

The RegExp says that: Digits OR Symbols (){}?!$&%*=+-. must be used -and that's what doesn't work, the OR operator, as I can insert both numbers and symbols-, at least one lowercase, at least one uppercase and a minimum lenght of 8 characters.

I've tried to use the OR operator | in several ways, but I can't make it work.

What am I missing? Thank you very much in advance.

Note: I'm using this regular expression within a liferay configuration file for the password policies.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
agapitocandemor
  • 696
  • 11
  • 25
  • To my knowledge, the OR operator in regex, like in most other situations, is inclusive, not exclusive, so it'll accept both as being ok. I could very well be wrong on this, not too familiar with regex. – MattS Jul 12 '12 at 16:21
  • Note that you shouldn't escape the usual special characters in a character class (inside `[]`). The only special characters there are `]`, `\ `, `-` and `^`. – Keppil Jul 12 '12 at 16:35

4 Answers4

3

You want a XOR logical operation, not a OR.

OR is true:
A |  B |  o/p
T |  T |   T
F |  T |   T
T |  F |   T
F |  F |   F

XOR is true:
A |  B | o/p
T |  T |  F
F |  T |  T
T |  F |  T
F |  F |  F

Exclusive Or in Regular Expression

Community
  • 1
  • 1
Lee Louviere
  • 5,162
  • 30
  • 54
3

Ok, I've rewritten your expression slightly, this is what I came up with:

String pattern = "^(?=.*[\\d().{}?!$&*%=+_-])(?=.*[a-z])(?=.*[A-Z]).{8,}$";

This matches any string with

  • at least one number or special character
  • at least one lower-case letter
  • at least one upper-case letter
  • is at least 8 characters long
Keppil
  • 45,603
  • 8
  • 97
  • 119
2

I have to say that, while regex can probably do this, I think it's simpler and safer to use multiple regex tests, something like:

boolean containsDigit = Pattern.matches("[0-9]", testString);
boolean containsSymbol = Pattern.matches("[(){}?!$&%*=+.-]", testString);
boolean containsLowercase = Pattern.matches("[a-z]", testString);
boolean containsUppercase = Pattern.matches("[A-Z]", testString);

if(testString.length() >= 8
        && containsLowercase
        && containsUppercase
        && (containsDigit || containsSymbol)
        && !(containsDigit && containsSymbol)) {
    //valid
} else {
    //invalid
}

I was using a Java regex pattern a few months ago that was not wildly complex, but it led to a Java bug being revealed. Too many parenthetic clauses seemingly caused trouble, and I had to split the pattern into something simpler.

The above is much more readable than a multi-clause regex pattern, and therefore easier to maintain and debug.

Bobulous
  • 12,967
  • 4
  • 37
  • 68
1

You said,

I can insert both numbers and symbols

That would be normal with a logical OR operation. It sounds like what you want is exclusive or (XOR). I'm afraid I don't know how you do that in regex, but hopefully this will point you in the right direction.

Martin McCallion
  • 743
  • 1
  • 4
  • 22