Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
508 views
in Technique[技术] by (71.8m points)

passwords - Regex to find 3 out of 4 conditions

My client has requested that passwords on their system must following a specific set of validation rules, and I'm having great difficulty coming up with a "nice" regular expression.

The rules I have been given are...

  • Minimum of 8 character
  • Allow any character
  • Must have at least one instance from three of the four following character types...
    1. Upper case character
    2. Lower case character
    3. Numeric digit
    4. "Special Character"

When I pressed more, "Special Characters" are literally everything else (including spaces).

I can easily check for at least one instance for all four, using the following...

^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?d)(?=.*?[^a-zA-Z0-9]).{8,}$

The following works, but it's horrible and messy...

^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?d)|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?d)(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?d)(?=.*?[^a-zA-Z0-9])).{8,}$

So you don't have to work it out yourself, the above is checking for (1,2,3|1,2,4|1,3,4|2,3,4) which are the 4 possible combinations of the 4 groups (where the number relates to the "types" in the set of rules).

Is there a "nicer", cleaner or easier way of doing this?

(Please note, this is going to be used in an <asp:RegularExpressionValidator> control in an ASP.NET website, so therefore needs to be a valid regex for both .NET and javascript.)

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not much of a better solution, but you can reduce [^a-zA-Z0-9] to [W_], since a word character is all letters, digits and the underscore character. I don't think you can avoid the alternation when trying to do this in a single regex. I think you have pretty much have the best solution.

One slight optimization is that d*[a-z]w_*|d*[A-Z]w_* ~> d*[a-zA-Z]w_*, so I could remove one of the alternation sets. If you only allowed 3 out of 4 this wouldn't work, but since d*[A-Z][a-z]w_* was implicitly allowed it works.

(?=.{8,})((?=.*d)(?=.*[a-z])(?=.*[A-Z])|(?=.*d)(?=.*[a-zA-Z])(?=.*[W_])|(?=.*[a-z])(?=.*[A-Z])(?=.*[W_])).*

Extended version:

(?=.{8,})(
  (?=.*d)(?=.*[a-z])(?=.*[A-Z])|
  (?=.*d)(?=.*[a-zA-Z])(?=.*[W_])|
  (?=.*[a-z])(?=.*[A-Z])(?=.*[W_])
).*

Because of the fourth condition specified by the OP, this regular expression will match even unprintable characters such as new lines. If this is unacceptable then modify the set that contains W to allow for more specific set of special characters.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...