orbnexus
orbnexus

Reputation: 807

How to create regex for passwords validate with length 8 - 24 and contain at least 3 of the following: lowercase, uppercase, numbers, special char

I want to use java-script to validate following criteria for password.

a.A password of at least 8 and no more than 24 characters is required.

b.Every password must contain at least three of these four types of characters:

1.an upper case letter

2.a lower case letter

3.a number

4.a special character.

I have found this code which is really easy and hand-full but it is just checking all 4 conditions not just at-least 3 conditions out of 4.

"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,24}"

I will really appreciate if you help me to figure out to create javascript validation on password to full fill my above requirement.

Thank you all for your help. I have modified @Ehtesham code and achieved the functionality.

function isValidPassword(pass) {
    var lowerRegex = /[a-z]/;
    var upperRegex = /[A-Z]/;
    var numberRegex = /[0-9]/;
    var specialRegex = /[$@$!%*?&]/;
    var count = 0;
    if (pass.length < 8 || pass.length > 24) {
        return false;
    }
    if (pass.match(lowerRegex)){count += 1;}
    if (pass.match(upperRegex)){count += 1;}
    if (pass.match(numberRegex)){count += 1;}
    if (pass.match(specialRegex)){count += 1;}    
    if (count >= 3){
        return true;
    }else{
        return false;   
    }
}

Upvotes: 1

Views: 2127

Answers (4)

bcre8ve
bcre8ve

Reputation: 1

This builds on Ehtesham's answer to require 3 out of 4:

function isValidPassword(pass) {
    var lowerRegex   = /[a-z]/;
    var upperRegex   = /[A-Z]/;
    var numberRegex  = /[0-9]/;
    var specialRegex = /[$@$!%*?&]/;
    var mustBe3 = 0;

    if(pass.length < 9 || pass.length > 24) { return false; }
    if(pass.match(lowerRegex))  { mustBe3 ++; }
    if(pass.match(upperRegex))  { mustBe3 ++; }
    if(pass.match(numberRegex)) { mustBe3 ++; }
    if(pass.match(specialRegex)){ mustBe3 ++; }

    // for testing ...
    if(window.console) console.log('pass: '+pass+' mustBe3: '+mustBe3);

    if( mustBe3 >= 3 ) { return true; }
    return false;
}

Upvotes: 0

Ehtesham
Ehtesham

Reputation: 2985

In javascript you can use following simple function.

function isValidPassword(pass) {
    var lowerRegex = /[a-z]/;
    var upperRegex = /[A-Z]/;
    var numberRegex = /[0-9]/;
    var specialRegex = /[$@$!%*?&]/;

    if (pass.length < 8 || pass.length > 24) {
        return false;
    }

    if (pass.match(lowerRegex) && pass.match(upperRegex) &&     
        pass.match(numberRegex) && pass.match(specialRegex)) {
        return true;
    }

    return false;
}

Jsfiddle demo

Upvotes: 1

aliteralmind
aliteralmind

Reputation: 20163

Please consider bookmarking the Stack Overflow Regular Expressions FAQ for future reference. There is a password validation entry under

"Common validation tasks > Internet"

That said, this seems like a pretty easy task if you break it up, as others have suggested. Mashing up all those requirements into a single regex, although an interesting exercise, is overkill in my opinion.

(This is Java, but there are equivalent concepts in JavaScript.)

public bolean isPasswordValid(String password)  {
   if(!length in bounds)  {
       return  false;
   }

   boolean hasUpper = Pattern.compile("[a-z]").find(password);
   boolean hasLower = Pattern.compile("[A-Z]").find(password);
   boolean hasDigit = Pattern.compile("[0-9]").find(password);
   boolean hasSpecialChar = Pattern.compile("...NOT SURE OF THIS ONE...").find(password);

   int types = (hasUpper ? 1 : 0) + (hasLower ? 1 : 0) +
               (hasDigit ? 1 : 0) + (hasSpecialChar ? 1 : 0);

   return  (types >= 3);
}

And if this is a function that will be used rapid fire, then you'll likely want to pre-compile and store those Matchers.

Upvotes: 2

dognose
dognose

Reputation: 20909

The regex you provided is made out of 5 major parts:

  • The pattern validating the length: [A-Za-z\d$@$!%*?&]{8,24}
  • A positive lookahead for at least one lowercase: (?=.*[a-z])
  • A positive lookahead for at least one uppercase: (?=.*[A-Z])
  • A positive lookahead for at least one number: (?=.*\d)
  • A positive lookahead for at least one special char: (?=.*[$@$!%*?&])

Now, you only want to apply 3 out of the 4 positive lookaheads. Since lookaheads are non-consuming matches, the cursor of the regex-engine will remain unchanged, as the matching is going on. (Using positive Lookaheads this way is often used to generate AND-Patterns)

So, you now have 4 conditions and you want that only 3 of them are matched. As described, it would be easy to use independent expressions and check if 3 apply. However, some native features (for instance jsf's f:validateRegex) only work with a single pattern.

Regular Expressions are supporting OR in a native way: | - hence to turn your expression 1 AND 2 AND 3 AND 4 into a minimum requirement of matching 3 of them, you could use an expression like (1 AND 2 AND 3) OR (1 AND 2 AND 4) OR (1 AND 3 AND 4) OR (2 AND 3 AND 4), which would cover all usecases required:

1   2   3   4
1   1   1   0
1   1   0   1
1   0   1   1
0   1   1   1

So, to match all this within a single pattern, just rearange your lookaheads as required:

^(?:(?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*[$@$!%*?&])|(?=.*[a-z])(?=.*\d)(?=.*[$@$!%*?&])|(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&]))[A-Za-z\d$@$!%*?&]{8,24}$

Drilldown:

^(?:                                     - non matching group
  (?=.*[a-z])(?=.*[A-Z])(?=.*\d)         - one lower, one upper, one number
  |                                      - or
  (?=.*[a-z])(?=.*[A-Z])(?=.*[$@$!%*?&]) - one lower, one upper, one special
  |                                      - or
  (?=.*[a-z])(?=.*\d)(?=.*[$@$!%*?&])    - one lower, one number, one special  
  |                                      - or
  (?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])    - one upper, one number, one special
 )
 [A-Za-z\d$@$!%*?&]{8,24}$               - 8 to 24 chars.

(Debuggex is using javascript)

^(?:(?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*[$@$!%*?&])|(?=.*[a-z])(?=.*\d)(?=.*[$@$!%*?&])|(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&]))[A-Za-z\d$@$!%*?&]{8,24}$

Regular expression visualization

Debuggex Demo

Upvotes: 4

Related Questions