Regular expression for a string that must contain minimum 14 characters, where at minimum 2 are numbers, and at minimum 6 are letters

I need a regex that tests a string for a

  • minimum of 14 characters - valid are A-Za-z0-9#,.-_
  • minimum of 6 letters within that 14
  • minimum of 2 numbers within that 14

Is there a way I can wrap this up in one regular expression (currently I have a javascript and php function that does three separate tests, one that it is 14 total, another that there is at least two numbers, and another that there is at least 6 letters.

So the following would be valid:

  • blabla2bla2f54a (valid >14 total, with at least 6 letters, at least 2 numbers)
  • thisIsNotValidAtAll (invalid because less than 2 numbers)

Answers:

Answer

Easy! First lets look at a commented version in PHP:

$re = '/# Match 14+ char password with min 2 digits and 6 letters.
    ^                       # Anchor to start of string.
    (?=(?:.*?[A-Za-z]){6})  # minimum of 6 letters.
    (?=(?:.*?[0-9]){2})     # minimum of 2 numbers.
    [A-Za-z0-9#,.\-_]{14,}  # Match minimum of 14 characters.
    $                       # Anchor to end of string.
    /x';

Here is the JavaScript version:

var re = /^(?=(?:.*?[A-Za-z]){6})(?=(?:.*?[0-9]){2})[A-Za-z0-9#,.\-_]{14,}$/;

Addendum 20121130:

I noticed that this answer recently got an upvote. This uses a more outdated expression so I figured it was time to update it with a better one...

a more efficient expression:

By getting rid of the dot-star altogether and greedily applying a more precise expression, (a negated char class), an even more efficient solution results:

$re = '/# Match 14+ char password with min 2 digits and 6 letters.
    ^                              # Anchor to start of string.
    (?=(?:[^A-Za-z]*[A-Za-z]){6})  # minimum of 6 letters.
    (?=(?:[^0-9]*[0-9]){2})        # minimum of 2 numbers.
    [A-Za-z0-9#,.\-_]{14,}         # Match minimum of 14 characters.
    $                              # Anchor to end of string.
    /x';

Here is the new JavaScript version:

var re = /^(?=(?:[^A-Za-z]*[A-Za-z]){6})(?=(?:[^0-9]*[0-9]){2})[A-Za-z0-9#,.\-_]{14,}$/;

Edit: Added #,.-_ to list of valid chars.
Edit: Changed the greedy to lazy star.
Edit 20121130: Added alternate version with the lazy-dot-star replaced with a more efficient greedy application of a more precise expression.

Answer

I would recommend multiple checks, writing a single regex for this would be ugly. Multiple checks also allows you to know what criteria wasn't met.

$input = 'blabla2bla2f54a';
$errors=array();
if (!preg_match('/^[A-Za-z0-9#,.\-_]*$/', $input))
    $errors[] = 'Invalid characters';
if (strlen($input) < 14)
    $errors[] = 'Not long enough';
if (strlen(preg_replace('/[^0-9]/','',$input)) < 2)
    $errors[] = 'Not enough numbers';
if (strlen(preg_replace('/[^A-Za-z]/','',$input)) < 6)
    $errors[] = 'Not enough letters';

if (count($errors) > 0) //Didn't work
{
    echo implode($errors,'<BR/>');
}
Answer
echo preg_match("/(?=.*[#,.-_])((?=.*\d{2,})(?=.*[a-zA-Z]{6,}).{14,})/", $string);

Output:

blabla2bla2f54a (1)
thisIsNotValidAtAll (0)
Answer

No, that's not possible, because in fact you want to do three individual checks. You can't wrap them up in one expression that returns true or false. The problem is, that you have two equal checks that you would need to combine via an AND-operator, whicht is not possible. But what we can do is building a super-size RegExp that recognizes every possible case. But hat kind of RegExp is senseless, because it would take a long time to apply this test on your string. I would recommend you doing three separated tests:

var result = string.replace(/[A-Za-z]{6}/, "").replace(/[0-9]{2}/, "").replace(/[A-Za-z0-9#,\.\-]{6}/, "").length == 0 ? true : false; // By shortening our sting we're saving time on later chained replacement methods

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.