【问题标题】:Regex: number of times repeated for a digit validation正则表达式:数字验证重复的次数
【发布时间】:2021-10-08 10:43:23
【问题描述】:

想通过以下几点找到有效的 10 位数字。

  • 10 位整数
  • 没有特殊字符的数字
  • 一个数字,其中第一个数字不能为零
  • 一个十位数字,其中一个数字恰好出现两次或三次,一位或两位数字出现零次,其他数字恰好出现一次。

前 3 个点可以用 (^[1-9])(\d{9}) 验证,简单的正则表达式。

试图为最后一点(secondPattern)找到有效的正则表达式。

试过了:

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

source

但是找不到。这里有任何帮助。

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
    );
}

并欢迎任何其他解决方案。 提前致谢。

【问题讨论】:

  • 不确定这意味着什么one or two digits appear zero times and the other digits appear exactly once.

标签: java regex


【解决方案1】:

不要尝试使用正则表达式来检测这一点。很难做到这一点,因为满足各种要求的数字可以出现在字符串中的任何位置。

计算每个数字出现的次数,然后检查条件:

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);

【讨论】:

    【解决方案2】:

    我认为正则表达式在这里不必“太”难。我的尝试是:

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

    在线查看demo


    • ^ - 起始线锚点。
    • (?!\d*(\d)\d* - 捕获第一个捕获组的负前瞻,然后是一个非捕获组来测试:
      • (\d)\d*\1\d*\2 - 4 个相同的字符或两个加扰的双精度字符 23423
      • | - 或者:
      • \1\d*(\d)\d*\3 - 两个非加扰双打 22344
    • 0 - 负前瞻内的外部交替以防止前导零。
    • (?=\d*(\d).*\4) - 一个积极的前瞻来检查是否有双重。
    • \d{10} - 正好 10 位数字。
    • $ - 结束线锚。

    【讨论】:

    • 这是一项巨大的努力,但对于 1223456891 这样的值却失败了,尽管存在两个 1 和两个 2,但它仍然匹配。除了最后一个之外,所有\d 都可以替换为. 以减少长度 - 您可能必须扩展它才能使正则表达式充分发挥作用。
    • @MikeM,你有鹰眼。感谢您的反馈。你介意根据你的回复测试^(?!.*(.)(?:.*(.).*(?:\1.*\2|\2.*\1)|.*\1.*(.).*\3)|0)(?=.*(.).*\4)\d{10}$吗?
    • 是的,我已经测试过了,效果很好。这是一个非常聪明的正则表达式。
    【解决方案3】:

    不确定是否完全正确地阅读了这个问题。
    这是一个正则表达式,我认为这是我解释它们的所有要求。

    1- 最佳点是找到 v 或 3 重复号码。
    2- 然后确保没有 4 重复号码。
    3-(添加)然后检查没有不同的2重复号码

    因为断言是原子的,所以在 1 & 2 & 3 之间有一个交集
    两者都为真,这将满足整个条件。


    ^(?!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
    

    【讨论】:

    • 错误地匹配了 1134567898 这样的值,它有两个 1 和两个 8。
    • @MikeM 如果不止一组重复,这有关系吗?
    • 我认为“其他数字只出现一次”很清楚。
    • @MikeM - 好的,添加了一个检查是否没有其他不同的 set 2 dup nums。就像我说的那样,我没有读到任何内容...
    • 是的,现在可以使用了。^(?=.*(.).*\1)(?!0|.*(.)(?:.*\2){3}|.*(?!\1)(.).*\3)\d{10}$ 是一个较短的版本。
    猜你喜欢
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-25
    • 2020-09-16
    • 2015-07-04
    • 1970-01-01
    相关资源
    最近更新 更多