Reputation: 58182
I need a regex that tests a string for a
A-Za-z0-9#,.-_
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:
Upvotes: 6
Views: 14783
Reputation: 34395
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,}$/;
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.
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,}$/;
#,.-_
to list of valid chars.Upvotes: 17
Reputation: 8541
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
Upvotes: -1
Reputation: 19380
echo preg_match("/(?=.*[#,.-_])((?=.*\d{2,})(?=.*[a-zA-Z]{6,}).{14,})/", $string);
Output:
blabla2bla2f54a (1)
thisIsNotValidAtAll (0)
Upvotes: 2
Reputation: 8700
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/>');
}
Upvotes: 5