I am working with resetting passwords. I need a way in java using regular expressions to reset the password so it cannot contain 4 consecutive characters from the previous password.
Regular expressions isn't solution to every world problem. You code would be much simpler and clearer if you implemented this as normal loop with 'indexOf' check.
edit
I'm assuming you plan to use it in some application. If you ask just out of curiosity, then I don't know :)
I don't think that regular expression is an apropriate tool for this task.
Actually, I can't see any other solution then a loop which will try to find a substring of 4 common characters.
You'll have to build that dynamically. Say you have a previous password of 'tiddlywinks'. That would mean the following are not allowed:
tidd iddl ddly dlyw lywi ywin inks
Just so happens it's nice and ends on a 4 character boundary. Didn't plan that one. Anyway. Walk through your previous password like so:
public Pattern toValidationExpression( String previousPassword ) {
StringBuilder builder = new StringBuilder();
for( int i = 0; i < previousPassword.length()-4; i++ ) {
if( i > 0 ) builder.append( "|" );
builder.append( "(" );
builder.append( previousPassword.substring(i, Math.min( i+4, previousPassword.length() );
builder.append( ")" );
}
return Pattern.compile( builder.toString() );
}
With some reasonable restrictions, this can in fact be done quite easily with regex.
Assuming that \n
is an illegal part of the password (VERY reasonable restriction), then the following code will do the check quite readably (if you know how to read regex):
static boolean legalChange(String before, String after) {
String joined = String.format("%s\n%s", before, after);
return !joined.matches(".*(.{4}).*\n.*\\1.*");
}
Here's a test harness (see also on ideone.com):
String[][] tests = {
{ "abcdef", "ghijklm" }, // true
{ "abcdef", "xbcdeyz" }, // false
{ "abcdef", "fedbcda" }, // true
{ "xyz", "" }, // true
{ "0123456789", "abc123def456ghi" }, // true
{ "0123456789", "abc123456ghi" }, // false
};
for (String[] test : tests) {
System.out.println(legalChange(test[0], test[1]));
}
Note that this regex only checks for the "no common substring of length 4" rule. Additional password regex rules must also be in place.
How it works
Essentially we combine the two strings into one, delimited by \n
(which again is an illegal character to have in usernames anyway).
This regex, then, will match an ILLEGAL change:
before | after i.e. before = .* (.{4}) .*
| after = .* \1 .*
.*(.{4}).*\n.*\1.*
\____/
1
That is, we match and capture (.{4})
from before
into group 1, and use backreference \1
to see if it can be matched in after
. We put .*
around those two to allow the occurrence to happen anywhere. The regex engine will do all the necessary backtracking on the .*
to see if this pattern can match.
Since that pattern matches an ILLEGAL change, we negate the result of matches
with the boolean
complement operator !
.
This is not the most efficient solution for the problem, but assuming that passwords are of reasonable length, speed will not be an issue.