Complex regex with preg_match_all()

Posted on 2012-08-13
Medium Priority
Last Modified: 2012-08-13
Dear Experts,

I've been handed a request to enforce a criteria for a password policy.

I will the be the first to say regular expressions are not my strong suit. So, while this may not be as complex as it seems, it most certainly is to me.

The request is:

two of a capital, special character, or number.

I understand the individual checks:


It's how to combine them and create the AND/OR that slips past me.

I considered doing it by keeping track of the individual results and doing a comparison afterward, but it occurred to me there must be a way to do it in one expression.

So, my question is - is there a way to do this in one expression and, if so, how?

Alternately, would it be cleaner to check the $subject individually and compare the results afterwards?

I am trying desperately not to break the rules by asking more than one question with this question, but finding it extremely difficult. The reason is if an Expert with regular expressions says "do it individually" then there is no reason to pursue the other option. If the best approach is to combine the checks into one expression, of course this is the route I would like to pursue, and learn from.

Thank you in advance.

Question by:mwheeler_fsd
  • 5
  • 2
  • 2
  • +1
LVL 35

Accepted Solution

Terry Woods earned 1400 total points
ID: 38289805
I'll assume you mean this, logically:
two of (a capital, special character, or number)
rather than:
two each of:
1. capitals
2. special characters
3. numbers

There's also a question of how you define special characters, as there are things like carriage returns and tabs to consider. I'll go by what's available on my (US) keyboard.


Open in new window

My code for testing:
$subjects = array("asdf2j",
"               "

foreach ($subjects as $subject) {
  if (preg_match("/^(?=(.*?[A-Z\d~!@#\$%\^&*()_+{}|:\"<>?`\-=\[\]\\\\;\',.\/]){2})/",$subject,$m
  #if (preg_match("/^(?=(.*?[A-Z\d]){2})/",$subject,$matches))
    print "Subject '$subject' matched\n";
    print "Subject '$subject' didn't match\n";

Open in new window

Subject 'asdf2j' didn't match
Subject 'FF' matched
Subject '**' matched
Subject 'jF' didn't match
Subject 'F' didn't match
Subject '' didn't match
Subject '\\' matched
Subject '\' didn't match
Subject '               ' didn't match

Open in new window

LVL 75

Assisted Solution

by:käµfm³d 👽
käµfm³d   👽 earned 600 total points
ID: 38289891
You may find my article, Regular Expression Lookaround Demystified, interesting to read. I give an example of setting up password requirements in the section "Real World Examples" (about half-way down).

My offering is:

preg_match('/^(?=[^A-Z0-9\W]*[A-Z0-9\W]+[^A-Z0-9\W]*[A-Z0-9\W])/', $subject, $matches);

Open in new window

I reused your "\W", but I agree with Terry's approach that you should explicitly define your "special characters". "\W" encompasses too many characters that I would not expect you would want in your passwords--including null characters! This is why Terry's last example would be matched by my pattern.

Author Comment

ID: 38289961
Yes, your assumption on the logic was correct. I had the opportunity to go through the spec on a conference call where that had been cleared up. When I posted the question, I cut and pasted it from the spec doc. Apologies for my assumptive oversight.

In any event, thank you for your excellent solution!

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.


Author Comment

ID: 38289977
I would also like to thank kaufmed for your insight, and will definitely check out your article.

LVL 111

Expert Comment

by:Ray Paseur
ID: 38290317
... it occurred to me there must be a way to do it in one expression ...
But why? Why not write simple, easy-to-understand code?

But with that said, please bookmark a link to the REGEX cheat sheet, where Dave Child has some helpful information for those of us, myself included, who are thickheaded about regular expressions.

HTH, ~Ray

Author Closing Comment

ID: 38290335
Dear TerryAtOpus and Kaufmed,

Please accept my humble explanation for a redistribution of my earlier awarded points.

I have been a member of EE for 8 years, and a programmer for 25 years. While I strive to follow the protocol, I was a bit hasty, and most certainly naive, about how to award points for your excellent answers. So much so, I consulted one of the outstanding mediators (who I will leave nameless, but greatly appreciated) as to what the proper protocol would be in this scenario, and my dilemma.

He offered up a well balanced explanation of the different ways these situations could be approached and, after more consideration, I feel I must award kaufmed a portion of the points.

The last thing I want to do is discourage or upset any of the Experts that work so hard to provide solutions, so please accept my apology for this. Here is my reasoning;

TerryAtOpus - your answer was spot on, and even having to take some assumptions from my lack of clarity, you solved the issue at hand. However, kaufmed's additional link to his excellent article was very helpful for me in understanding why/how this works.

I realize that the goal is to answer the question, but the additional foundation information from kaufmed helps me to improve as a programmer. I clearly understand that was not what I asked for, and I am hoping, with the deepest respect, you can understand my reasoning.

I take this site very seriously and hope that both of you will understand why, and how, I arrived at this conclusion.

Your time and dedication is greatly appreciated.

With best regards,

PS - Again through my own hard lesson learned, I must thank Ray_Paseur for his response as well. I apologize for this, and most certainly have a better understanding of the protocol and workings in this scenario. My naivete in this situation is quite humbling.
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 38290382
Unexpected, but appreciated  = )

Author Comment

ID: 38290388
You are quite welcome and I hope my explanation is well received. Your article is excellent.

Best regards,
LVL 35

Expert Comment

by:Terry Woods
ID: 38290436
Thanks, Mike, for caring about the people at the other end! It's appreciated!

Author Comment

ID: 38290446
Thank you SO much for understanding. A learning experience for me, and am truly appreciative of the gracious understanding.

Best wishes to all,

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
This holiday season, we’re giving away the gift of knowledge—tech knowledge, that is. Keep reading to see what hacks, tips, and trends we have wrapped and waiting for you under the tree.
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Suggested Courses
Course of the Month16 days, 13 hours left to enroll

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question