1

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; } } 
12
  • 7
    Why is there an upper limit on the password length? Are you not hashing them in your database? Commented Mar 5, 2015 at 20:05
  • 6
    Split this into 4 regexes, and test them separately. Commented Mar 5, 2015 at 20:05
  • Why the low upper limit? Commented Mar 5, 2015 at 20:09
  • 2
    For what it's worth, you should advise your client that an upper limit is a really bad idea. Commented Mar 5, 2015 at 20:23
  • 2
    Somebody always asks this question. It can't be done using JavaScript regex because it doesn't do conditionals. If it did conditionals, the regex is easy. 3/4, 2/9, 10/30, it's always the same format /^(?:.*?(?:((?(1)(?!))[A-Z]+)|((?(2)(?!))[a-z]+)|((?(3)(?!))[0-9]+)|((?(4)(?!))[!@#$%^&*()\[\]_+}{?><,.\/":;'-]+))){3}.*$/ Commented Mar 5, 2015 at 20:25

4 Answers 4

4

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

Sign up to request clarification or add additional context in comments.

6 Comments

Permutations is the only way. What would it look like with 4 out of 5 ?
@sln Permutations can be generated easily (little code). Not a real problem.
Will get strange with 3 of 5.
@sln ofc. it becomes hard to read - but if the scenario requires a single pattern, there is no other option.
That's awesome work, @dognose. A regex this complicated speaks to just how much regex should not be used to solve the OP's problem. At least, not solving the whole problem in a single regex.
|
2

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.

Comments

1

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

1 Comment

Basically my answer converted to JavaScript, which is fine. The requirement is "at least three" special char types, not "all four".
0

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; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.