0

I have a pattern as below

pattern='(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[-+*/%])(?=.*[.?,:;-~]).*';

what I want is at least: One Upper Case Value One Lower-Case Value One Numeric Value One of each of the characters in the last two brackets.

However, my regex is not working properly (even when I have at least one of each it shows me an error)

What is the correct form of this pattern?

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
NateR
  • 85
  • 9
  • 2
    this problem does not lend itself to one regex. Do it in a regex for every case. – erik258 Aug 05 '21 at 00:40
  • @DanielFarrell I'm sorry I don't follow. Can you elaborate please? You don't mean a pattern attribute for each one right? – NateR Aug 05 '21 at 00:49
  • https://stackoverflow.com/questions/3466850/regular-expression-to-enforce-complex-passwords-matching-3-out-of-4-rules – MDR Aug 05 '21 at 01:06
  • Which test string did you use that contains at least one character in each class but does not match? Your regex as it is should match more than you expect it to because of the range notation `-` in the last character class. – blhsing Aug 05 '21 at 01:39
  • Does this answer your question? [Regular expression to enforce complex passwords, matching 3 out of 4 rules](https://stackoverflow.com/questions/3466850/regular-expression-to-enforce-complex-passwords-matching-3-out-of-4-rules) – AaronJ Aug 12 '21 at 15:16
  • You said "it shows me an error". What is that error? Never say "I got an error" without cutting & pasting what the error is, exactly. – Andy Lester Aug 12 '21 at 15:56

2 Answers2

4

You may use the principle of contrast, that is:

^                        # start of the string
(?=[^A-Z]*[A-Z])         # not A-Z, zero or more times, A-Z once
(?=[^a-z]*[a-z])         # ... same with lower case letters ...
(?=\D*\d)                # ... digits ...
(?=[^-+*/%]*[-+*/%])     # ... first "special character" ...
(?=[^-~.?,:;]*[-~.?,:;]) # ... second "special character" ...
.+                       # one character or more
$                        # end of the string

The method is as follows:

(?=[^characters I do not want]*[^characters I do want])
#  ^^^ - negation

See a demo on regex101.com (the newline characters there are only for the online tester).

Jan
  • 42,290
  • 8
  • 54
  • 79
1

It looks like you're trying to validate a password according to a set of rules. Don't try to do it in one regex. If your rules are:

  • One Upper Case Value
  • One Lower-Case Value
  • One Numeric Value
  • One of -+*/%

then do it as four different regexes.

In Perl, you would do it like

$password_is_valid =
    $pw =~ /[A-Z]/ &&   # uppercase 
    $pw =~ /[a-z]/ &&   # lowercase
    $pw =~ /[0-9]/ &&   # digit
    $pw =~ /[-+*/%];    # special char

That is far easier to read, understand and maintain than any single regex you might come up with.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152