正则表达式验证 3 个重复字符

Chr*_*ris 5 java regex

我正在尝试验证密码,无论它们在字符串中的位置如何,都不允许出现 3 个重复字符。

例如 :

121121 - 不接受,因为 1 出现超过 3 次。

121212 - 接受,因为 1 和 2 只出现了 3 次

我试过这个

([0-9])\1{2,}
Run Code Online (Sandbox Code Playgroud)

但它只验证连续重复的数字。

Jac*_* G. 5

我不建议对这样的事情使用正则表达式,因为将密码收集到Map维护每个字符计数的位置会更容易。然后,您可以检查是否存在计数大于 的任何字符3

password.chars()
        .boxed()
        .collect(Collectors.groupingBy(i -> i, Collectors.counting()))
        .values()
        .stream()
        .anyMatch(i -> i > 3);
Run Code Online (Sandbox Code Playgroud)

这将返回true如果存在某些字符password出现超过3次,false否则。


Wik*_*żew 4

正则表达式解决方案的效率非常低。请考虑纯粹出于学术兴趣来对待这个答案。

出现 4 次或多次相同字符的字符串失败的模式是

^(?!.*(.).*\1.*\1.*\1).*
Run Code Online (Sandbox Code Playgroud)

.*如果您需要精确该模式,则可以将最后一个模式替换为更具限制性的模式。

请参阅正则表达式演示

这里的主要部分是(?!.*(.).*\1.*\1.*\1)负前瞻。它匹配任何 0+ 字符(如果Pattern.DOTALL使用,则匹配任何字符,包括换行符),尽可能多,然后匹配并将任何字符捕获(使用(.))到组 1 中,然后匹配任何 0+ 字符后跟相同的字符 3 次。如果找到(匹配)模式,则整个字符串匹配失败。

为什么效率低下?该模式很大程度上依赖于回溯。.*抓取字符串末尾的所有字符,然后引擎回溯,尝试为后续子模式容纳一些文本。您可能会在此处看到回溯步骤。数量越多.*,该模式就越消耗资源。

为什么惰性变体没有更好?对于某些字符串,看起来^(?!.*?(.).*?\1.*?\1.*?\1).*速度更快,如果重复字符彼此靠近并且与字符串的开头靠近,速度也会更快。如果它们位于字符串的末尾,效率就会降低。因此,如果前一个正则表达式匹配12121277 个步骤,则当前正则表达式也将采用相同数量的步骤。然而,如果你对其进行测试1212124444,你会发现惰性变体将在 139 步后失败,而贪婪变体将在 58 步后失败。反之亦然,4444121212将导致惰性正则表达式失败得更快,14 个步骤vs. 211 个步骤(贪婪变体)

在Java中,你可以使用它

s.matches("(?!.*(.).*\\1.*\\1.*\\1)")
Run Code Online (Sandbox Code Playgroud)

或者

s.matches("(?!.*?(.).*?\\1.*?\\1.*?\\1)")
Run Code Online (Sandbox Code Playgroud)

在生产中使用Jacob 的解决方案