1

By using regex, I am trying to validate a user input as he types.

My pattern is this: "(\\w{3})(\\d{7})(\\w{3})". A valid input can be "XYZ0001112CCC".

I want to validate it as user types. I mean "A", "AB", "ABC", "ABC12", "ABC123", ..., "ABC1234567XY" should also not fail. But "A1", "AB2", "ABCD123", ..., "ABC1234567XY1" must fail. As long as the input doesn't break the rule, I want to assume it as "valid so far". Is this possible with regex?

4 Answers 4

1

I would use a combination of "once or not at all" quantifier for the each following part after the first letters, and lookbehinds to validate the previous parts of the input.

For instance:

//                           |first letters (1 to 3)
//                                        | if 3 letters precede...
//                                                         | digits (1 to 7)
//                                                                   | if 7 digits precede...
//                                                                               | 3 letters
Pattern p = Pattern.compile("[a-zA-Z]{1,3}((?<=[a-zA-Z]{3})\\d{1,7})?((?<=\\d{7})[a-zA-Z]{3})?");
String[] inputs = {"XYZ0001112CCC", "A", "AB", "ABC", "ABC12", "ABC123", "A1", "AB2", "ABCD123","ABC1234567XY1"};
Matcher m;
for (String input: inputs) {
    m = p.matcher(input);
    System.out.println("Input: " + input + " --> Matches? " + m.matches());
}

Output:

Input: XYZ0001112CCC --> Matches? true
Input: A --> Matches? true
Input: AB --> Matches? true
Input: ABC --> Matches? true
Input: ABC12 --> Matches? true
Input: ABC123 --> Matches? true
Input: A1 --> Matches? false
Input: AB2 --> Matches? false
Input: ABCD123 --> Matches? false
Input: ABC1234567XY1 --> Matches? false

Note

I've changed your \\w expression to character class [a-zA-Z] because \\w also validates digits. Alternatives to [a-zA-Z] are:

  • \\p{Alpha}
  • [a-z] with Pattern.CASE_INSENSITIVE flag on

Final note

My Pattern takes the last letters as a 3-letter group. If you would also accept 1 or 2 letters, you only need to change the last quantifier expression {3} with {1,3}.

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

4 Comments

why ABC12 or ABC123 returns false?
@Tim my bad, I used the "once or not at all" quantifier for the whole input following the 1st 3 letters. Fixed.
Thanks @Mena. It seems ok now. I am not familiar with regex much. But do you suggest regex for such situations? It works but is it also ok in performance considerations. Is this a convenient situation for regex usage?
@Tim I think regex is ok for this and the actual Pattern does not have that much overhead, under the circumstances (you might want to compile it as a constant --> static final instead of recompiling it every time). As per regex complexity in this case, it's not that complex. For instance, take a look at some e-mail validation patterns out there... those are complex ;)
1

You could change the pattern to simpler one ([a-zA-Z]+)(\d+)([a-zA-Z]+)

Then you could check how many letters was in each group:

Pattern p = Pattern.compile("([a-zA-Z]+)(\d+)([a-zA-Z]+)");
Matcher matcher = p.matcher("ABC1234567XYZ");
if (matcher.find()) {
    String firstLetters = matcher.group(1);
    String digits = matcher.group(2);
    String lastLetters = matcher.group(3);

    //any checks here
}

3 Comments

IllegalStateException: No match found.
Strange that it did not find a match. I also updated pattern, since \w takes also underscore + numbers and + is required for at least one match.
I think your suggested pattern must be: ([a-zA-Z]*)(\\d*)([a-zA-Z]*). This is a good solution too, but Mena's solution seems better to me since all checks done within regex.
0

I recommend you split your validation into two separate regular expressions: one for the valid-so-far validation and one for the final check.

Even then, it's not trivial to validate that e.g. ABC1 is valid so far. A pattern like (\\w{0,3})(\\d{0,7})(\\w{0,3}) won't cut it because X0C would be incorrectly considered valid. I therefore recommend you don't try to solve this problem with regular expressions alone, but with some coded logic.

(It is possible to squeeze all the validation logic into a single regular expression using either lookbehinds or if-then-else conditionals, but I suggest not to do that. It's unreadable and unmaintainable.)

2 Comments

Do you have any "valid-so-far" suggestion? Would't there be many possibilities?
@Tim You can fit it all into one regular expression, like Mena shows in his answer, although you'll have to judge for yourself whether you accept that complexity.
0

Since the format is rather easy, you could do something like this (I don't know the exact java syntax, but I think the idea is clear):

String input = "DEF3";
String example = "ABC1234567XY";
Pattern regex = Pattern.compile("(\\w{3})(\\d{7})(\\w{3})");

String test_input = input + example.last_digits(example.length-input.length);
Matcher matcher = p.matcher(test_input);
return matcher.find();

This way the only duplication you have is between the example and the regex.

Comments

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.