I agree with the statements of the previous replies you probably shouldn't do this in a single regex. Doing it in multiple also allows you to show more specific error messages indicating what the problem is, instead of a long list of requirements the user then have to read through to figure out which one they are missing. This is how I recommend doing it.
And as mentioned in previous replies -
always do the check on the server side, and optionally do it in JavaScript to provide instant feedback to the user.
That said, it is fairly simple to do it in a single regex, using "Lookahead Zero Length Assertions". OriginalGriff was very close in his answer, but did not quite reach the simplicity you can (or I missed something that prevents this approach from working).
The trick is to start the match with ^. This "anchors" everything you do at the start.
You then concatenate a lookahead zero length assertion for each rule you have. This works, as your zero length assertions do not move the position in the string. After each of them, the regex is still looking at the start of the string and can simply keep checking rules.
So we start with:
^
Add the rule it must be followed by at least 8 characters
^(?=.{8,})
Then add your special characters (you probably want more than these, this is just an illustration). Notice I prefix it with ".*". This skips over any non-special character so it no longer matters which position the special character is in. Remember to escape for JavaScript and Regex as needed (I was lazy and only chose characters where no escaping is needed).
^(?=.{8,})(?=.*[!#¤%&_-])
Now repeat this construct for alphabet (ignoring "lower/upper case" which you can trivially add, as well as the fact alphabet is language specific - i.e. why not accents or even Chinese characters - look into Regex character ranges for more information)
^(?=.{8,})(?=.*[!#¤%&_-])(?=.*[a-zA-Z])
Throw in the requirement for a digit:
^(?=.{8,})(?=.*[!#¤%&_-])(?=.*[a-zA-Z])(?=.*\d)
While the regex can looks a bit daunting, it is a very simple construct with each rule having it's own "top level parenthesis" - and no dependencies between the rules - so when you add/modify you do not need to go through all the other rules to make sure they still work. While the length increase for each rule, the complexity pretty much stays the same.
Make sure you add comments about how it is build up. Or maybe even better: Put each rule into a clearly named string, for example:
minLength = "(?=.{8,)"
, and then build the final regex as
"^" + minLenght + specialCharacter + atLeastOneDigit + ...
This will both keep the individual rules easy to read and "document" how the regex is build up. But it would also mean you could as well run the regexes one by one as originally suggested.
Notice the regex will not generate a match over the password. I.e. it will tell you the password is valid, but if you ask the regex how many characters it matched, it will say 0. If this is a problem, postfix your final regex with
.*$
, so it looks like this:
^(?=.{8,)(?=.*[!#¤%&_-])(?=.*[a-zA-Z])(?=.*\d).*$