1

I am working on password enhancement and client wants a password that does not have consecutive letters ie: 123, 234.

I have figured out that you can declare strings that you want to match in regex like (012|123|234|345|456|567|678|789|890) and made it as the regex sequence.

This sequence is separated from the other sequences for easy reading.

The problem is, I cannot match the password with the pattern even if I included 123 or 234 in the password character.

I've read that regex cannot detect 123 as consecutive numbers, but as a string, can it do so?

dixienormous
  • 117
  • 1
  • 4
  • 12
  • Regexes are always working on strings. They have no idea about the meaning of the characters, e.g. they don't know that 2 is one more than 1 – stema Jul 18 '13 at 05:49
  • Please post your code with the string that is not matched and where you apply the regex. – stema Jul 18 '13 at 05:50

2 Answers2

3

If you're only dealing with these strings of digits that you want to exclude, you can achieve this using a negative lookahead assertion:

^(?!.*(012|123|234|345|456|567|678|789|890))<regex>

where <regex> is the actual regex you're using to match the password, and (?!...) is the lookahead that asserts it's impossible to match that string in your regex.

If you're asking about any increasing sequence of characters, then regex is not the right tool for this. You would have to do that programmatically.

Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • Why not just use `.find()` and invert the test? – fge Jul 18 '13 at 05:50
  • @fge: Sure, if you want to do a series of tests one after another instead of a single large (possibly unwieldy) regex, that would be a valid strategy as well. – Tim Pietzcker Jul 18 '13 at 05:52
  • @TimPietzcker I am using 6 regex patterns now to check for the other requirements. – dixienormous Jul 18 '13 at 05:59
  • That will quickly become unsustainable... Find another strategy to test for passwords – fge Jul 18 '13 at 06:00
  • @user2571732: Well, you can put multiple checks into a regex, and if you use `Pattern.COMMENTS` mode, you can even write them understandably (and possibly easier to read than a complicated programmatic solution. YMMV). See for example http://stackoverflow.com/questions/3802192/regexp-java-for-password-validation – Tim Pietzcker Jul 18 '13 at 06:24
3

If you have a limited sequence of characters following one another you can use a Pattern, .find() on a matcher on your input and just invert the test:

// Only the alternation is needed, no need for the capture
private static final Pattern PATTERN
    = Pattern.compile("012|123|234|345|456|567|678|789|890");

// ...

if (PATTERN.matcher(input).find())
    // fail: illegal sequence found

But if you want to detect that code points follow one another you have to use character functions:

final CharBuffer buf = CharBuffer.wrap(input);

int maxSuccessive = 0;
int successive = 0;
char prev = buf.get();
char next;

while (buf.hasRemaining()) {
    next = buf.get();
    if (next - prev == 1)
        successive++;
    else {
        maxSuccessive = Math.max(maxSuccessive, successive);
        successive = 0;
    }
    prev = next;
}

// test maxSuccessive

Note however that this will test successive characters according to "canonical ordering", not collation. In some locales, for instance, what is immediately after a is A, not b.


More generally, if you want to test for password requirements and constraint evolves, you are better off splitting things a bit. For instance, consider this:

public interface PasswordChecker
{
    boolean isValid(final String passwd);
}

Implement this interface for each of your checks (for instance, length, presence/absence of certain characters, etc), and when you do check for a password, have a List of checkers; the password is invalid if one checker returns false:

private final List<PasswordChecker> checkers = ...;

// then

for (final PasswordChecker checker: checkers)
    if (!checker.isValid(passwd))
        return false;
return true;

If you use Guava, you can forget about PasswordChecker and use Predicate<String>.

fge
  • 119,121
  • 33
  • 254
  • 329