1

Want to find valid 10-digit number with the following points.

  • a 10-digit integer number
  • a number without special characters
  • a number, where the first digit cannot be zero
  • a number with the ten digits having one number occurring exactly twice or thrice, one or two digits appear zero times and the other digits appear exactly once.

First 3 points can be validated with (^[1-9])(\d{9}), simple regex.

Trying to find valid regex for last point (secondPattern).

Tried:

(?:\d{2}){2,3} 
(?:\\d{2}){2,3}+(\\?:\\d){0,2}
(?s)(\\d)(?=.*\\1){2,3}

source

But could not find out. any help here.

private void validateNumber() {
    var basePattern = Pattern.compile("(^[1-9])(\\d{9})");
    var secondPattern = Pattern.compile("(?s)(\\\\d)(?=.*\\\\1){2,3}");
    var result = getNumbers()
            .stream()
            .filter(num ->basePattern.matcher(num).matches() &&
                    secondPattern.matcher(num).matches()
            ).collect(Collectors.toList());
    System.out.println(result);
}

private List<String> getNumbers() {
    return List.of(
            "1134567890",
            "2123456789",
            "1234267890",
            "1671812342",
            "1934466892:6",
            "1234@56789",
            "3563893124",
            "4412356789",
            "2349780915",
            "981651321182234556",
            "1234567890",
            "10000000000",
            "02346ex789",
            "0000%00000",
            "0234567 894",
            "8232527884",
            "02325278847",
            "02345678945",
            "2323456789",
            "8152228374",
            "0234527834",
            "8183746528",
            "0435465768",
            "3245657689"
            //etc
    );
}

and welcome any other solutions. Thanks in advance.

Md. Fazlul Hoque
  • 15,806
  • 5
  • 12
  • 32
Ravichandra
  • 1,260
  • 7
  • 23
  • 37
  • Not sure about what this means `one or two digits appear zero times and the other digits appear exactly once.` – sln Oct 08 '21 at 21:42

3 Answers3

4

Don't try to detect this with a regex. It's hard to do that because the digits meeting the various requirements can appear anywhere in the string.

Do it by counting the number of occurrences of each digits, then check the conditions:

if (input.length() != 10) {
  return false;
}
// a number, where the first digit cannot be zero
if (input.startsWith("0")) {
  return false;
}

int[] counts = new int[10];
for (int i = 0; i < input.length(); ++i) {
  char c = input.charAt(i);
  if (c < '0' || c > '9') {
    // Not a number.
    return false;
  }

  counts[c - '0']++;
}

// Now check your requirements:

// having one number occurring exactly twice or thrice
if (IntStream.of(counts).filter(c -> c == 2 || c == 3).count() != 1) {
  return false;
}
// one or two digits appear zero times
long zeros = IntStream.of(counts).filter(c -> c == 0).count();
if (zeros != 1 && zeros != 2) {
  return false;
}
// and the other digits appear exactly once.
return IntStream.of(counts).filter(c -> c != 2 && c != 3 && c != 0).allMatch(c -> c == 1);
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
3

I don't think the regular expression has to be 'too' difficult here. My attempt was:

^(?!\d*(\d)\d*(?:(\d)\d*\1\d*\2|\1\d*(\d)\d*\3)|0)(?=\d*(\d).*\4)\d{10}$

See an online demo


  • ^ - Start line anchor.
  • (?!\d*(\d)\d* - A negative lookahead to catch a 1st capture group followed by a non-capture group to test for:
    • (\d)\d*\1\d*\2 - Either 4 of the same characters or two scrambled doubles 23423.
    • | - Or:
    • \1\d*(\d)\d*\3 - Two doubles non-scrambled 22344.
  • 0 - The outer alternation inside the negative lookahead to prevent leading zeros.
  • (?=\d*(\d).*\4) - A positive lookahead to check that there is a double.
  • \d{10} - Exactly 10 digits.
  • $ - End line anchor.
JvdV
  • 70,606
  • 8
  • 39
  • 70
  • It's a great effort but fails for values such as `1223456891`, which it matches despite there being two 1s and two 2s. All the `\d` except the last one could be replaced by `.` to reduce the length - which you are probably going to have to extend to make the regex work fully. – MikeM Oct 08 '21 at 16:45
  • @MikeM, you got the eye of an hawk. Thanks for the feedback. Do you mind testing `^(?!.*(.)(?:.*(.).*(?:\1.*\2|\2.*\1)|.*\1.*(.).*\3)|0)(?=.*(.).*\4)\d{10}$` in light of your response? – JvdV Oct 08 '21 at 17:26
  • 1
    Yes, I've tested it and it works well. It's a very smart regex. – MikeM Oct 08 '21 at 17:42
1

Not sure if reading the question entirely right.
Here is a regex with I think as all requirements as I interpreted them.

1- The sweet spot is finding a v or 3 dupe number.
2- Then making sure there is no 4 dupe number.
3- (added) Then check there is not different 2 dupe number

Since asserts are atomic, there is an intersection between 1 & 2 & 3 where
both are true which will satisfy the entire condition.


^(?!0)(?=\d{10}$)(?=.*?(.)(?:.*\1){1,2})(?!.*?(.)(?:.*\2){3})(?!.*?(?!\1)(.).*\3).*

https://regex101.com/r/IcoYYt/1

 ^                             # Beginning
                               # Look ahead's
 (?! 0 )                       # Not 0 first
 (?= \d{10} $ )                # Ten dig's total
 (?=                           # Any two or three dup nums 
    .*? 
    ( . )                         # (1)
    (?: .* \1 ){1,2}
 )
 (?!                           # Not any four dup nums 
    .*? 
    ( . )                         # (2)
    (?: .* \2 ){3}
 )
 (?!                           # Not any other two dup nums 
    .*? 
    (?! \1 )
    ( . )                         # (3)
    .* \3 
 )
 .*                            # Consume line
sln
  • 2,071
  • 1
  • 3
  • 11