Trouble With Regex

Any questions involving matching text strings to patterns - the pattern is called a "regular expression."

Moderator: General Moderators

Post Reply
Superman859
Forum Commoner
Posts: 47
Joined: Sun Oct 29, 2006 10:22 am

Trouble With Regex

Post by Superman859 »

I'm just starting to learn Regex and am having trouble coming up with an expression.

Basically I want a to verify a password matches criteria. It needs to be at least 6 characters long, have at least 1 uppercase, 1 lowercase, and 1 number. That is all the criteria.

I realize I could put this together very easily without using regex at all, but since I am beginning to study regex, I want to try and write it out in regex.

I tried what is below, but it doesn't seem to work. It simply returns a match if the password is 6 characters or longer, but isn't requiring at least 1 of each. I'm sure it's a simple problem but I'm just starting with regex.

[[a-z]+[A-Z]+[0-9]+]{6,}
User avatar
GeertDD
Forum Contributor
Posts: 274
Joined: Sun Oct 22, 2006 1:47 am
Location: Belgium

Post by GeertDD »

Hmm, interesting question. I'm learning regular expressions myself as well and can't think of a one-line solution for now.

You could of course apply different regexes to make sure the password matches all the criteria.

Code: Select all

function password_is_safe($str) {
  return (
    preg_match('/[A-Z]/', $str)
    && preg_match('/[a-z]/', $str)
    && preg_match('/[0-9]/', $str)
    && preg_match('/^.{6,}$/', $str)
  );
}
However, this is not an efficient setup. If you do it this way, you'd better use faster functions like strlen() and strpos(), as you probably already realized. I just couldn't think of a single regex. I'll be watching this topic.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Code: Select all

^[[:alnum:]]{6,25}^
alphanumeric characters between 6 and 25 chars.

although for this you won't need regex, simply ctype_alpha() and strlen() would do the trick and is faster.

Code: Select all

if (strlen($input) > 6) and ctype_alpha($input))
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Re: Trouble With Regex

Post by volka »

But that doesn't check for
Superman859 wrote:It needs to be at least 6 characters long, have at least 1 uppercase, 1 lowercase, and 1 number.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Re: Trouble With Regex

Post by John Cartwright »

volka wrote:But that doesn't check for
Superman859 wrote:It needs to be at least 6 characters long, have at least 1 uppercase, 1 lowercase, and 1 number.
My bad, I kinda just looked at the second post.
Superman859
Forum Commoner
Posts: 47
Joined: Sun Oct 29, 2006 10:22 am

Post by Superman859 »

Yea, it's not too bad creating one that is alphanumeric and at least 6 characters...

I'm actually writing the pattern for a Java program i was working on, which uses the same regex patterns for the most part.

I know how to do it all separately. I can check to see if it is alphanumeric and at least 6 characters in one step, and then qualify the others (at least 1 of each) using a for loop and boolean variable. However, since I have begun to learn regex, I was wondering if it's possible to do it all with one pattern. I would have thought you could, but I haven't figured it out.
User avatar
sweatje
Forum Contributor
Posts: 277
Joined: Wed Jun 29, 2005 10:04 pm
Location: Iowa, USA

Post by sweatje »

This is probably not the best tool for the job, but just for fun, here is a regex which seems to fit the bill, tested using a SimpleTest test case:

Code: Select all

function testSixOrMore1Up1Down1NumWithRegex() {
	$regex = '~^([a-z](?=[a-z]*([A-Z]+[a-z]*[0-9]|[0-9]+[a-z]*[A-Z]))
		|[A-Z](?=[A-Z]*([a-z]+[A-Z]*[0-9]|[0-9]+[A-Z]*[a-z]))
		|[0-9](?=[0-9]*([A-Z]+[0-9]*[a-z]|[a-z]+[0-9]*[A-Z])))
		[A-Za-z0-9]{5,}$~x';
	
	$this->assertTrue(preg_match($regex, 'Ab1234'),'ok');
	$this->assertTrue(preg_match($regex, 'AAbb11'),'ok');
	$this->assertTrue(preg_match($regex, 'bb11AA'),'ok');
	$this->assertTrue(preg_match($regex, '11bbAA'),'ok');
	$this->assertFalse(preg_match($regex, '123456'),'all num, should fail');
	$this->assertFalse(preg_match($regex, 'AaBbCc'),'all alpha, should fail');
	$this->assertFalse(preg_match($regex, 'Ab124'),'too short, should fail');
	$this->assertFalse(preg_match($regex, 'ab1234'), 'no upper, should fail');
	$this->assertFalse(preg_match($regex, 'Ab1!34'), 'special char, should fail');
}
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

Found this one on RegExpLib. Searched for 'password'

Code: Select all

<?php
// Makes sure there is at least one UPPER case letter, one lower case and one number, and that it is between 4 and 8 chars long
// Change the 4 and 8 to your min and max length requirements
$pattern = '^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{4,8}$';
?>
User avatar
sweatje
Forum Contributor
Posts: 277
Joined: Wed Jun 29, 2005 10:04 pm
Location: Iowa, USA

Post by sweatje »

Hi Everah,

That is a much better regex, it would fail for the last test case, but can be easily tweaked to work correctly:

Code: Select all

function testSixOrMore1Up1Down1NumWithRegex() {
	$regex = '~^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{6,}$~';
	
	$this->assertTrue(preg_match($regex, 'Ab1234'),'ok');
	$this->assertTrue(preg_match($regex, 'AAbb11'),'ok');
	$this->assertTrue(preg_match($regex, 'bb11AA'),'ok');
	$this->assertTrue(preg_match($regex, '11bbAA'),'ok');
	$this->assertFalse(preg_match($regex, '123456'),'all num, should fail');
	$this->assertFalse(preg_match($regex, 'AaBbCc'),'all alpha, should fail');
	$this->assertFalse(preg_match($regex, 'Ab124'),'too short, should fail');
	$this->assertFalse(preg_match($regex, 'ab1234'), 'no upper, should fail');
	$this->assertFalse(preg_match($regex, 'Ab1!34'), 'special char, should fail');
}
Superman859
Forum Commoner
Posts: 47
Joined: Sun Oct 29, 2006 10:22 am

Post by Superman859 »

Yes, that is certainly a better pattern.

That makes use of lookahead's, correct? I don't know much about them as I'm just starting to learn regex, but it seems to make sense in this case and I actually understand the pattern![/img]
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Yes, lookaheads.

Here is a nice cheat sheet (PDF): http://www.phpguru.org/downloads/PCRE%2 ... 0Sheet.pdf
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Post by kaisellgren »

This will check that $a has atleast 6 letters and max 25 while it checks that $a has atleast 1 low letter, 1 upp letter and 1 number. It also accepts characters like å, ß, etc...

Code: Select all

if (preg_match("/\p{Ll}.*\p{Lu}|\p{Lu}.*\p{Ll}/",$a) && preg_match("/\d/",$a) && preg_match("/^\p{L}{6,25}$/",$a))
 echo "$a is valid!";
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Post by kaisellgren »

Everah | Split regex pattern so it doesn't break the layout of the boards.

Okay. Now I spent couple of minutes on this and tested it and works great.

This regex checks you have atleast 1 lower-,1uppercahracter and 1 number. This does not check the length though.

Code: Select all

$pattern  = "/([a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*[\d]|[A-Z][a-zA-Z0-9]*[a-z][a-zA-Z0-9]*[\d]";
$pattern .= "|[a-z][a-zA-Z0-9]*[\d][a-zA-Z0-9]*[A-Z]|[\d][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*[a-z]|";
$pattern .= "[A-Z][a-zA-Z0-9]*[\d][a-zA-Z0-9]*[a-z]|[\d][a-zA-Z0-9]*[a-z][a-zA-Z0-9]*[A-Z])/";
preg_match($pattern, $a);
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

There is not easier or cleaner regex than that monstrosity? :wink:
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Post by kaisellgren »

Everah wrote:There is not easier or cleaner regex than that monstrosity? :wink:
Yes there is. Something I made with my two friends once we were bored. This pattern can be used for complete Email check (RFC822). Not 100% sure it works but looks like.

Code: Select all

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(?:(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|"(?:[^"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:".\[\] \x00-\x1F]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*))*)?;\s*)
I just love regular expressions!

Code: Select all

((I|you|we|they)\s+love|s?he\s+loves)\s*reg(ular expressions?|ex(p|es)?)
Post Reply