ChatGPT解决这个技术问题 Extra ChatGPT

RegEx to make sure that the string contains at least one lower case char, upper case char, digit and symbol

What is the regex to make sure that a given string contains at least one character from each of the following categories.

Lowercase character

Uppercase character

Digit

Symbol

I know the patterns for individual sets namely [a-z], [A-Z], \d and _|[^\w] (I got them correct, didn't I?).

But how do I combine them to make sure that the string contains all of these in any order?

What platform/regex-dialect? Bart's answer is right, but lookahead assertions aren't reliable in JavaScript, for example.
Nowhere in particular - I'm learning regex. Is there an alternative that can be used in javascript?
@bobince Hey, I am trying to find out why lookahead assertions aren't reliable in Javascript. Is there a writeup on this?
@ChrisB: There's a really confusing IE/JScript bug: blog.stevenlevithan.com/archives/regex-lookahead-bug

B
Bart Kiers

If you need one single regex, try:

(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)

A short explanation:

(?=.*[a-z])        // use positive look ahead to see if at least one lower case letter exists
(?=.*[A-Z])        // use positive look ahead to see if at least one upper case letter exists
(?=.*\d)           // use positive look ahead to see if at least one digit exists
(?=.*\W)           // use positive look ahead to see if at least one non-word character exists

And I agree with SilentGhost, \W might be a bit broad. I'd replace it with a character set like this: [-+_!@#$%^&*.,?] (feel free to add more of course!)


What would happen if i change the last .+ into .*? I couldn't come up with a test case that fails with .*. Are they same in this context? "Zero or more characters" seems to be fine - just seeking confirmation.
@Amarghosh: in this case, it makes no difference. Because of the positive look-aheads, the string already contains at least 4 characters. So it makes no difference to change .+ into .* or even .{4,} for that matter.
If you would be willing to add a little explanation, I am having trouble understanding how the combination of these lookaheads guarantees at least 1 of each character set will be present
@BartKiers What if I don't want any symbol? removing (?=.*[_\W]) doesn't work regex101.com/r/jH9rK1/1
@ikertxu, try something like this: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?!.*[&%$]).{6,}$
E
Elijah Mock

Bart Kiers, your regex has a couple issues. The best way to do that is this:

(.*[a-z].*)       // For lower cases
(.*[A-Z].*)       // For upper cases
(.*\d.*)          // For digits
(.*\W.*)          // For symbols (non-word characters)

In this way you are searching no matter if at the beginning, at the end or at the middle. In your have I have a lot of troubles with complex passwords.


You're not checking for symbols as the OP requested.
This will only wotk if lower case, upper case and digit are found in this order. For example ist does not work with 111aaqBBB
S
SilentGhost

You can match those three groups separately, and make sure that they all present. Also, [^\w] seems a bit too broad, but if that's what you want you might want to replace it with \W.


Thanks. I wasn't aware of \W. Just looked it up to find that it matches Not Word. Is there any difference between \W and [\W]? Is [\W] just redundant?
@Amarghosh, yes, \W and [\W] result in the same.
E
Ensei_Tankado

Bart Kiers solution is good but it misses rejecting strings having spaces and accepting strings having underscore (_) as a symbol.

Improving on the Bart Kiers solution, here's the regex:

(?=.\d)(?=.[a-z])(?=.[A-Z])((?=.\W)|(?=.*_))^[^ ]+$

A short explanation:

(?=.*[a-z])        // use positive look ahead to see if at least one lower case letter exists
(?=.*[A-Z])        // use positive look ahead to see if at least one upper case letter exists
(?=.*\d)           // use positive look ahead to see if at least one digit exists
(?=.*\W)           // use positive look ahead to see if at least one non-word character exists
(?=.*_)           // use positive look ahead to see if at least one underscore exists
|           // The Logical OR operator
^[^ ]+$           // Reject the strings having spaces in them.

Side note: You can try test cases on a regex expression here.