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]
withPattern.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}
.