tags:

views:

113

answers:

4

Here it is:

/(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/

It only passes if the password contains upper case AND lower case letters, and also either 1 digit or 1 special character, however I want underscore _ to count as a special character as well and it currently does not, how can modify this regex so that it will allow underscore to count as a special character?

EDIT: here is the context...

jQuery.validator.addMethod("complexity", function(value, element) {
    return this.optional(element) || /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/.test(value);
}, "password is not complex, see requirements above");
+3  A: 

Any particular reason you want to do all of this in one regex? Seems to me this would be a lot more readable if you just broke it down:

 if (password.length() < 8) return "Password too short!";
 if (!password.matches("\d")) return "Password must contain at least one digit!";
 if (!password.matches("[A-Z]")) return "Password must contain at least one uppercase leter!";
 if (!password.matches("[a-z]")) return "Password must contain at least one lowercase leter!";

 // Password is valid, save it, etc.
zigdon
see the EDIT made to see why, it's already implemented this way :)
shogun
@Shogun: Why not factor out the checking into a function and then you can just call `validate_complexity(value)` instead of `//.test(value)`? Factoring it out is much more maintainable and readable
Daenyth
telling me to change what I am doing is not answering my question
shogun
Nod - I wasn't trying to say you should change what you are doing, just take a moment to make sure you aren't looking in the wrong place :) Note I didn't say "You shouldn't use RE here!".
zigdon
+3  A: 

I suppose your \W denotes a special character (It's usually defined as "A non-word character")

So, if you would like to add _ to that set of characters, you should be able to write [\W_].

(Updated according to Scott Chamberlains comment.)


I'm not sure why you have (?![.\n]). Do you want to prevent newlines in the password?

Otherwise, this looks like a simplified regexp:

String regexp = "(?=^.{8,}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[\\W_\\d]).*$";
for (String s : new String[] {
        "abcdefg",
        "abcdefgh",
        "abCdefgh",
        "abc1efgh",
        "abC1efgh",
        "abC1e@gh",
        "abC1e_gh"}) {

    System.out.println(s + " is " + (s.matches(regexp) ? "ok" : "not ok"));

}

Prints

abcdefg is not ok
abcdefgh is not ok
abCdefgh is not ok
abc1efgh is not ok
abC1efgh is ok
abC1e@gh is ok
abC1e_gh is ok
aioobe
Most regex languages count _ as a word charater http://www.regular-expressions.info/charclass.html#shorthand
Scott Chamberlain
yeah I would figure as much too but it isn't count it when I try
shogun
[^\w_] is incorrect that would be equilivant to [^a-zA-Z0-9__] (notice the two underscores) what you want is [\W_] which is equilvant to [^a-zA-Z0-9_]|_
Scott Chamberlain
Thanks. Updated!
aioobe
cool, an upvote for your efforts but the other guy dropped this one first, thanks guys
shogun
+4  A: 
/(?=^.{8,}$)((?=.*\d)|(?=.*[\W_]+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/

aioobe was close replace \W with [\W_]

Just so you know this considers a space a special character.

Also I don't see where you are checking for numbers. EDIT: nevermind I found it. (man complex regexes are like a wheres waldo.)

Here is a simplifed version that does not allow spaces (and it is easyier to maintain)

(?=^.{8,}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_\d])(?=^.*[^\s].*$).*$
^          ^          ^          ^            ^
|          |          |          |            L--does not contain a whitespace
|          |          |          L--at least one non word charter(a-zA-Z0-9_) or _ or 0-9
|          |          L--at least one upper case letter
|          L--at least one lowercase Letter
L--Number of charaters

These are your building blocks

(?=.*[a-z]) // Whatever is inside the [] meens the string contains at least one charter inside that set.
            // If you wanted a minimum of three lowercase letters you can chain the inner block like so 
               (?=(.*[a-z]){3,})
Scott Chamberlain
you were first with this so you got it, worked like a charm
shogun
Speaking of that empty space, how would I make it so empty space was not allowed?
shogun
@Shogun I added some more explanation and a example without white space (but I don't see a legitimate reson for not allowing it)
Scott Chamberlain
`(?=^.*[^\s].*$)` doesn't exclude whitespace, it just ensures that there is at least one non-whitespace character.
Alan Moore
@Alan Moore thanks, I removed the incorrect sections.
Scott Chamberlain
cool thanks, you are right now that I think about it, it might as well be allowed
shogun
+3  A: 

Do you consider this an acceptable password?

Aa8 ½ý_

Because your regex matches it. You might want to change that first lookahead from (?=^.{8,}$) to (?=^[!-~]{8,}$), limiting the possibilities to printing ASCII characters (i.e., not whitespace or control characters). If you want to allow non-ASCII characters it gets a lot more complicated; JavaScript regexes don't do Unicode very well.

Here's how I would write the regex:

/^(?=[!-~]{8,}$)(?=.*[A-Z])(?=.*[a-z])(?=.*[^A-Za-z]).*$/

Like Scott, I don't see the point of this bit: (?![.\n]). All it does is make sure the first character is not a period or a linefeed. That can't be what you (or the original author) meant, but I can't even guess what the actual intent was.

Alan Moore