1

I need to know how the regex is for the following case:

  • At least 8 characters ( ... ).{8,}
  • Has letters (?=.*[a-z|A-Z])
  • Has numbers (?=.*\d)
  • Has special characters (?=.*[~'!@#$%?\\\/&*\]|\[=()}"{+_:;,.><'-])

I got the following based in other regex:

((?=.*\d)(?=.*[a-z|A-Z])(?=.*[~'!@#$%?\\\/&*\]|\[=()}"{+_:;,.><'-])).{8,}

But it fails for:

qwer!234

Any tips?

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
Marcos Vasconcelos
  • 18,136
  • 30
  • 106
  • 167

4 Answers4

4

In a Java regex, you need to double the backslashes because of string escaping rules:

Pattern regex = Pattern.compile("^(?=.*\\d)(?=.*[a-zA-Z])(?!\\w*$).{8,}");

should work.

Explanation:

^              # Start of string
(?=.*\d)       # Assert presence of at least one digit
(?=.*[a-zA-Z]) # Assert presence of at least one ASCII letter
(?!\w*$)       # Assert that the entire string doesn't contain only alnums
.{8,}          # Match 8 or more characters
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
1

With all those special characters, it's moderately likely that you didn't escape everything properly.

You said Java right? This prints true:

String regex = "((?=.*\\d)(?=.*[a-zA-Z])(?=.*[~'!@#$%?\\\\/&*\\]|\\[=()}\"{+_:;,.><'-])).{8,}";
System.out.println("qwer!234".matches(regex));

But this is quite a bit simpler:

String regex = "(?=.*?\\d)(?=.*?[a-zA-Z])(?=.*?[^\\w]).{8,}";
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • That doesn't make any difference. Each lookahead starts from the same position at the start of the string. – Tim Pietzcker Mar 05 '13 at 20:20
  • @TimPietzcker Edited. I think I was thinking of something like `.*(?=c).*` but it matches `abcd`. Where is `*?` required then? – Bernhard Barker Mar 05 '13 at 20:33
  • Very rarely, for example if you expect multiple matches in a string and want to avoid matching both at once: Compare `<.*>` vs. `<.*?>` for matching `" "`. – Tim Pietzcker Mar 05 '13 at 20:35
  • Well, I believe I didn't escaped everything correctly, but the second regex solved my problem, ty! – Marcos Vasconcelos Mar 05 '13 at 20:52
  • @MarcosVasconcelos I suspect that the last element `[^\\w]` will allow to enter spaces and tabs into the "recognized" string. ::: For example "qwer! 2 3 4" would match. ::: Maybe you should add spaces to the list `[^\\w\\s]` – ilomambo Mar 07 '13 at 13:07
1

Why put this all in a single regular expression? Just make separate functions for each check and your code will be much easier to understand and maintain.

if len(password) > 8 &&
   has_alpha(password) &&
   has_digit(password) &&
    ...

Your business logic is instantly undertandable. Plus, you don't have to modify a tricky regular expression when you want to add some other condition.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • i do not want to check it in a bunch of ifs, a regex is pretty cool :p – Marcos Vasconcelos Mar 05 '13 at 20:49
  • 1
    @MarcosVasconcelos: "cool" isn't always the best solution. As you gain experience as a programmer you'll come to realize that clarity is considerably more important. If you had taken this simpler solution, you would be done and already on your way to working on something much more interesting than password validation. – Bryan Oakley Mar 05 '13 at 20:52
  • Yeah.. as I gained my experience, I realized that regex is always cool and legible (with correctly documentation) inside the code – Marcos Vasconcelos Mar 05 '13 at 20:59
0
Pattern letter = Pattern.compile("[a-zA-z]");  
Pattern digit = Pattern.compile("[0-9]");  
Pattern special = Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");  
Pattern eight = Pattern.compile (".{8}");  
...  
public final boolean ok(String password) {  
   Matcher hasLetter = letter.matcher(password);  
   Matcher hasDigit = digit.matcher(password);  
   Matcher hasSpecial = special.matcher(password);  
   Matcher hasEight = eight.matcher(password);  
   return hasLetter.find() && hasDigit.find() && hasSpecial.find()  
      && hasEight.matches();  
}  

It will works.

Visme
  • 983
  • 8
  • 29