开发者

What is the Regular expression for following constraint?

开发者 https://www.devze.com 2023-03-08 16:45 出处:网络
I want a regular expression for a string for password that contain at least three out of the followi开发者_如何学运维ng four types of characters:

I want a regular expression for a string for password that contain at least three out of the followi开发者_如何学运维ng four types of characters:

  • English lowercase characters (a through z).
  • ENGLISH UPPERCASE CHARACTERS (A THROUGH Z).
  • Base 10 digits (0 through 9).
  • Non alphanumeric characters (e.g. !,$,#,%).

And should contain at least 8 character.


Given the monstrositya that these requirements are likely to generate, I suspect you're actually going to be better off doing this as multiple checks, something like (pseudo-code):

def check_password (s):
    if len(s) < 8:
        return false
    rules_followed = 0
    if match (s, "[a-z]") rules_followed++;
    if match (s, "[A-Z]") rules_followed++;
    if match (s, "[0-9]") rules_followed++;
    if match (s, "[!$#%]") rules_followed++;  # et cetera
    if rules_followed < 3:
        return false
    return true

This is likely to be much more readable when someone else has to maintain your code (or even if you have to maintain it six months from now).

Now I realise this may not always be possible (you may, for example, be stuck with a framework that only allows one regex for validation).

But, if it is possible, I strongly suggest you consider it. The first thing you should always try to optimise for is readability.


a You'll either end up with one of those massive lookahead regexes or a single regex containing the sixteen possibilities of ordering separated by |.

Neither of these are likely to be as efficient or readable as a simple code segment.


Expanded PCRE version of the regex:

/^(?:
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[a-z])         # look ahead: at least one from a-z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  |                   # or...
  (?=.*[A-Z])         # look ahead: at least one from A-Z
  (?=.*[0-9])         # look ahead: at least one from 0-9
  (?=.*[^a-zA-Z0-9])  # look ahead: at least one from special chars
  )
  \S{8,}              # at least 8 non-spaces
$/x


First, here's a C# translation of paxdiablo's code:

public bool Validate(string input)
{
    if (input == null || input.Length < 8)
        return false;
    int counter = 0;
    if (input.Any(Char.IsLower)) counter++;
    if (input.Any(Char.IsUpper)) counter++;
    if (input.Any(Char.IsDigit)) counter++;
    if (input.Any(c => Char.IsPunctuation(c) || Char.IsSymbol(c))) counter++;
    return counter >= 3;
}

If you insist on a regex, you can use a pattern similar to the one on Fun With .NET Regex Balancing Groups:

^
(?=.*[a-z](?<Counter>))?
(?=.*[A-Z](?<Counter>))?
(?=.*[0-9](?<Counter>))?
(?=.*[^a-zA-Z0-9](?<Counter>))?
(?<-Counter>){3}   # check we've had at least 3 groups
.{8}

You may also allow Unicode classes:

^
(?=.*\p{Ll}(?<Counter>))?
(?=.*\p{Lu}(?<Counter>))?
(?=.*\p{Nd}(?<Counter>))?
(?=.*[\p{S}\p{P}](?<Counter>))?
(?<-Counter>){3}
.{8}


The combinatorics aren't that bad -- there's only four ways to pick three out of four possibilities; you can test those with lookaheads at the start of the regex, and then check for eight characters with the actual match:

^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*\d)|(?=.*[A-Z])(?=.*[a-z])(?=.*[_\W])|(?=.*[A-Z])(?=.*\d)(?=.*[_\W])|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}

(The anchoring is for efficiency when failing, it would work without it).

It probably doesn't matter for a password, but the version above will potentially look through the whole string more than once for the same type of character, especially when failing. You might factor it out like this, at the cost of readability:

^(?:(?=.*[A-Z])(?:(?=.*[a-z])(?:(?=.*\d)|(?=.*[_\W]))|(?=.*\d)(?=.*[_\W]))|(?=.*[a-z])(?=.*\d)(?=.*[_\W])).{8}


Correct answer of my question :

regular Expression :

^((?=.[\d])(?=.[a-z])(?=.[A-Z])|(?=.[a-z])(?=.[A-Z])(?=.[^\w\d\s])|(?=.[\d])(?=.[A-Z])(?=.[^\w\d\s])|(?=.[\d])(?=.[a-z])(?=.[^\w\d\s])).{8,30}$

Thanks.

0

精彩评论

暂无评论...
验证码 换一张
取 消