Just add nested capture groups to save character checking not strictly as a sequence. The regular expression can also be simplified as follows (without additional groups):
(?=(?:.*[0-9]){2,20})
(?=(?:.*[a-z]){2,20})
(?=(?:.*[A-Z]){3,20})
(?=(?:.*[@#$%!&*?_~,-]){2,20})
.{9,20}
[^<>'\"] # This matches also the newline char, i don't think you really want this...
In java use it like this:
String regex = "(?=(?:.*[0-9]){2,20})(?=(?:.*[a-z]){2,20})(?=(?:.*[A-Z]){3,20})(?=(?:.*[@#$%!&*?_~,-]){2,20}).{9,20}[^<>'\"]";
String password = "23aaA@AA!@X";
if (password.matches(regex))
System.out.println("Success");
else
System.out.println("Failure");
For regular expression, a password is required with (everything is not strictly in sequence):
(?=(?:.*[0-9]){2,20}): 2 numbers(?=(?:.*[a-z]){2,20}): 3 lowercase lettes(?=(?:.*[A-Z]){3,20}): 3(?=(?:.*[@#$%!&*?_~,-]){2,20}): 2.{9,20}: 9 . 20[^<>'\"]: char, (<, >, ', ") (: )
, min/max 10/21, , - regex 9 20.
Regex -