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

13,354

Solution 1

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 2012-11-30

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 1: Added #,.-_ to list of valid chars.
  • Edit 2: Changed the greedy to lazy star.
  • Edit 2012-11-30: Added alternate version with the "lazy-dot-star" replaced with a more efficient greedy application of a more precise expression.

Solution 2

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/>');
}

Solution 3

echo preg_match("/(?=.*[#,.-_])((?=.*\d{2,})(?=.*[a-zA-Z]{6,}).{14,})/", $string);

Output:

blabla2bla2f54a (1)
thisIsNotValidAtAll (0)
Share:
13,354
Chris
Author by

Chris

Thanks for checking out my profile, hopefully one of my answers has helped you out. Shameless plug: 🍙 Are you learning Japanese? 🍙 We built https://imawakatta.com to make learning Japanese fun again. Plenty of free content

Updated on June 17, 2022

Comments

  • Chris
    Chris almost 2 years

    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)
  • Yzmir Ramirez
    Yzmir Ramirez about 13 years
    Should those be {2,}, {6,}, and {14,} since its "or more"? This is using the If-Then-Else syntax, right? regular-expressions.info/conditional.html
  • Chris
    Chris about 13 years
    @webarto seems very close, but doesn't work for aaa2aaaaaaaaaaaaa2aaa but does work for aaa2aaaaaaaaaaaaa22aaa. It seems the positive look ahead requires that there is 2 in sequence?
  • Dejan Marjanović
    Dejan Marjanović about 13 years
    Give me a minute, I'll figure it out :)
  • buschtoens
    buschtoens about 13 years
    Oh sorry, totally forgot about the use of (?=...). It's possible. webarto is right.
  • Dejan Marjanović
    Dejan Marjanović about 13 years
    @Chris, yes it looks in sequence, I can't get it work non sequential if it's possible at all.
  • Chris
    Chris about 13 years
    @ridgerunner I like it, and I pretty much understand it. I;m going to have to do a bit more reading on positive look ahead's I think. One question though, why is a minimum of 2/6 done as {2}/{6}, not {2,}/{6,}?
  • Chris
    Chris about 13 years
    @webarto Thanks for looking into it, it looks like you were really close! It appears ridgerunner has it pretty much spot on.
  • ridgerunner
    ridgerunner about 13 years
    @Cris: Since each requirement is only a minimum, once the minimum number is matched, there is no need to match any more (so why bother - just extra unnecessary work).
  • Chris
    Chris about 13 years
    @ridgerunner - just one more question, to include #,.-_ as per the question, I would just need to include them in the final clause [A-Za-z0-9#,\.-_]{14,0}, correct?
  • Dejan Marjanović
    Dejan Marjanović about 13 years
    @ridgerunner, is it possible to match #,.-_ 0 or more times :)?
  • david
    david about 13 years
    Almost, you need to escape the -character because it is used to specify ranges. so [A-Za-z0-9#,.\-_]{14,}
  • ridgerunner
    ridgerunner about 13 years
    David is correct. The - must be escaped in a char class (unless you place it at the very start or end). Personally, I like to escape it. Have updated the answer.
  • Dejan Marjanović
    Dejan Marjanović about 13 years
    @david @ridgerunner, you are right, if - is not escaped then ? can go through.
  • Chris
    Chris about 13 years
    @ridgerunner, @david, @webarto Thanks for discussing it and fleshing out the problem at hand. I am very happy with ridgerunners answer, and will mark his as correct. Thanks ridge
  • david
    david about 13 years
    @ridgerunner I see you removed the lazy star, you should probably put it back in as it saves a lot of backtracking and speeds things up quite a bit. Here is a testcase showing the difference: jsperf.com/regexquestionmarktest
  • ridgerunner
    ridgerunner about 13 years
    @david: You're right. I let a previous version slip back in on one of my edits. Thanks for the eagle eye!