1
System.out.println(Pattern.matches("[A-Z]{1,}[a-z]{1,}[0-9]{2,}[@#$%]+[ ]*", "DEFabc45$  "));

but it don't work When I pass string like passW@ord45. Mean I should not following regex order pattern written here.

Following are the conditions given bellow:

Write a function boolean isValidPassword (String password) A Password is valid if it satisfies following conditions:

  1. Length of the password must be more than 10 (without counting spaces).
  2. Password must contain at least one capital and one small alphabet
  3. Password must contain at least 2 digits and if it does not have 2 digits then see next condition.
  4. Password must contain at least one special character from the given set- {$, @, _, -, ., /}
posdef
  • 6,498
  • 11
  • 46
  • 94
Ramesh Kumar
  • 345
  • 1
  • 4
  • 10
  • this could help http://stackoverflow.com/questions/5068843/password-validation-regex – davide Feb 19 '15 at 12:16
  • 5
    Regex is the wrong tool here - while you *might* be able to code the requirements given it will result in a very complicated expression. It will almost certainly be impossible to understand and therefore maintain when you come back to it later. This would be much better solved using some simple code statements in Java and much, much more readable. – Paolo Feb 19 '15 at 12:20
  • Usually im all for regex but as soon as you go into 'if not this then' sort of logic, regex probably isnt the way. – Srb1313711 Feb 19 '15 at 12:57
  • @Srb1313711: Don't assume, learning, testing yourself, analyzing the situation are the only ways to not repeat "mainstream assertions". – Casimir et Hippolyte Feb 19 '15 at 13:02
  • @CasimiretHippolyte im not assuming anything im not even saying its not possible, all im saying is there are probably better ways to go about this – Srb1313711 Feb 19 '15 at 14:39

1 Answers1

1

You can use the method linked in @davide comment, so basically:

(?=(?: *\\S){10})(?=.*[a-z])(?=.*[A-Z])(?=.*[$@_./-]|.*[0-9].*[0-9])

However, using .* everywhere will produce a lot of backtracking (in particular .*[0-9].*[0-9]), so the way to prevent this is to be more explicit:

(?=(?: *\\S){10,})(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])[^$@_./0-9-]*+(?:[$@_./-]|[0-9][^0-9]*[0-9])

About features used in these two patterns:

\\S is a shorthand character class: all that is not a white-space character

(?=...) is a zero-width assertion (a test) called lookahead, and means followed by. So with it you can test several assertions from the same position like this: (?=..)(?=..)(?=..)... since characters are not consumed.

*Note that in the second pattern, I have choosen to not use the lookahead because since there are no more rules, it's not important to consume characters or not.

So each lookahead contains a rule:

rule 1: at least 10 non-space characters

(?=
    (?: *\\S){10}  # a group with optional spaces and one non space character
                   # the group is repeated 10 times, so there are at least
                   # 10 characters that are not a space
)

rule 2a: a lowercase letter

(?=
    [^a-z]*    # zero or more characters that are not a lowercase letter
    [a-z]      # until a lowercase letter
)

rule 2B: an uppercase letter, (same as 2a but with A-Z)

rules 3 et 4 are combined in one subpattern that is not in a lookahead as explained:

[^$@_./0-9-]*+          # all that is not a digit or a special character
                        # Note: I have added a possessive quantifier make the whole
                        # pattern to fail faster if the next group fails 
(?: # two possibilities:
    [$@_./-]            # a special character
  |                  # OR
    [0-9][^0-9]*[0-9]   # two digits: a digit, other characters, an other digit 
) 

You can use these patterns as it with lookingAt since there is no need to anchor them at the end (according to your requirements) or with matches but you need to add .* at the end to reach the end of the string.

Casimir et Hippolyte
  • 88,009
  • 5
  • 94
  • 125
  • "It will almost certainly be impossible to understand and therefore maintain when you come back to it later" I think you've illustrated my point nicely :D – Paolo Feb 19 '15 at 13:37
  • 1
    @Paolo: We can draw a parallel with learning to read: when you recognize the words and idiomatic expressions, constructions, you can immediately understand the meaning of a sentence. Not being able to understand a pattern (so basic and well known here) is due to a lack of skills. But if that skill is acquired, rewrite or modify such pattern takes 5 minutes shower included, as any other thing. – Casimir et Hippolyte Feb 19 '15 at 14:13
  • I think this solution is invalid. The condition reads: "without counting whitespaces". And not: "may not contain whitespaces". I think it is better to mix regexp where appropiate with "normal" checks and method calls like `.replace(" ","").length() > 10` etc. – UniversE Feb 19 '15 at 15:01
  • @UniversE: No, spaces are taken in account here: `(?: *\\S){10}`, the quantifier `*` makes the space(s) optional, so the `{10}` will repeat the non-space character 10 times. Note that to be more rigorous, you can write `(?:\\s*\\S){10}` *(but it's generaly difficult to put a tab or a newline in a password field, but who knows?)*. see here: https://regex101.com/r/yX1hP2/1 – Casimir et Hippolyte Feb 19 '15 at 15:11
  • @CasimiretHippolyte oh okay - now I get the idea... you capture a character and any preceeding whitespace and count it as one. So `____1|__2|___3|__________4|` and so on.. (where _ is a whitespace here) – UniversE Feb 19 '15 at 15:12
  • @UniversE: yes, the content of the non-capturing group is optional spaces and one non-space character, and the group is repeated 10 times. – Casimir et Hippolyte Feb 19 '15 at 15:13
  • @UniversE: I will detail my answer. – Casimir et Hippolyte Feb 19 '15 at 15:16