2

I need to check a login name. It has to (it's political, not technical decision) have:

  1. from 5 to 30 characters;
  2. characters must be from group [a-zA-Z0-9*];
  3. at least one character must be number;
  4. it's not possible to have all characters just from numbers if login name has 5 characters but if it has 6 or more character, it can be constructed just from numbers.

I have regexp (?=[a-zA-Z0-9*]*[0-9])[a-zA-Z0-9*]{5,30} which works for points 1-3, but can't imagine how to include check for point 4.

6
  • 1
    If you're going to be doing this in just Java, why not just use an if / else to break this into 2 regexes based on a count of characters? It's technically possible and I'm trying to whip it up now... Commented Jun 3, 2016 at 13:42
  • 1
    You could add a look-behing like (?![0-9]{5}$) Commented Jun 3, 2016 at 13:42
  • @SebastianProske that would not allow sequences of 5 digits at the end but what if the password is something like a12345? Commented Jun 3, 2016 at 13:46
  • @Thomas You should add the lookbehind in front (like the other one) and it will allow login names like a12345, see regex101.com/r/vY1vD7/1 Commented Jun 3, 2016 at 13:47
  • @SebastianProske looks like this works, thanks :) i'm checking it here Commented Jun 3, 2016 at 13:50

4 Answers 4

1

Use regex with negative look ahead assertion

(?!\d{5}$)(?=[a-zA-Z\d*]*\d)[a-zA-Z\d*]{5,30}

Regex explanation here.

Regular expression visualization

Sign up to request clarification or add additional context in comments.

Comments

1

It is always tempting to validate all aspects of a string using a single, pretty complicated regular expression. But keep in mind that this thing might be hard to extend, maintain in the future.

Meaning: depending on the rate of "changes" to your validation rules, there might be better designs. For example, one could envision something like:

interface NameValidator {
    isValid(String name) throws InvalidNameException;
}

class LengthValidator implements NameValidator ...
class XyzValidator implements NameValidator ...

class NameValidation {
   private final List validators = Arrays.toList(new LengthValidator(), ...

   void isValid(String name) {
      run all validators ...

This way, adding / changing one of your validation rules ... becomes much more straight forward ... than tampering a single regular expression, potentially breaking some other part of it.

Beyond that, you can even build different rule set; by combining different instances of NameValidation implementers; whilst avoiding code duplication .

Comments

0

As others have pointed out, you don’t have to do it with a single regex. Even if that’s possible, it will be obnoxiously complex and difficult for others to understand.

The simplest approach is the best:

boolean passwordValid = password.matches("[a-zA-Z0-9*]{5,30}")
    && password.matches(".*[0-9].*")
    && !password.matches("[0-9]{5}");

Comments

0

I'd like to propose a different approach: don't use a regex but check each character and collect password properties. That way you are able to implement more complex requirements later on, e.g. "it must have 3 out of 4".

Example:

String pw = "1a!cde";

Set<PwProperty> passwordProperties = new HashSet<>();
for( char c : pw.toCharArray() ) {
  if( isDigit( c ) ) { 
    passwordProperties.add( PwProperty.DIGIT ); 
  }
  else if ( isSpecialChar( c ) ) { 
    passwordProperties.add( PwProperty.SPECIAL); 
  }
  else if( isUpperCase( c ) ) {
    passwordProperties.add( PwProperty.UPPER_CASE); 
  }
  else if( isLowerCase( c ) ) {
    passwordProperties.add( PwProperty.LOWER_CASE); 
  }
  else {
    passwordProperties.add( PwProperty.UNKNOWN ); 
  }
}

Then you could check that like this (pseudo code):

if( !pw.length() in range ) {
   display "password too short" or "password too long"
}

if( passwordProperties.contains( PwProperty.UNKNOWN ) {
  display "unsupported characters used"
}

Set<PwProperty> setOf4 = { DIGIT, SPECIAL, LOWER_CASE, UPPER_CASE }
if( intersection( passwordProperties, setOf4 ).size() < 3 ) {
  display "use at least 3 out of 4"
}

if( !passwordProperties.contains( DIGIT ) ) {
  display "must contain digits"
}

display "password strength" being intersection( passwordProperties, setOfGoodProperties ).size()

etc.

This can then be expanded e.g. with properties like DIGIT_SEQUENCE which might be unwanted etc.

The main advantage is that you have more detailed information on the password rather than "it matches a certain regex or not" and you can use that information to guide the user.

2 Comments

there should be problem in case you need to use regex in config file
@LadislavDANKO that's true and that might be a reason not to use that approach. However, this is meant to provide more flexilibity expecially in guiding the user and still can be implemented in a way that allows for configuration via a text file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.