Reputation: 4673
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?
Upvotes: 1
Views: 324
Reputation: 4987
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
}
Upvotes: 1
Reputation: 4055
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.
Upvotes: 0
Reputation: 48434
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 onFinal 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}
.
Upvotes: 1
Reputation: 16470
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.)
Upvotes: 0