我试图验证密码,不管它们在字符串中的位置如何,都不应该允许3个重复字符。
例如:
121121 - 未接受,因为1出现超过3次。
121212 - 接受,因为1和2只出现3次
我试过这个
([0-9])\1{2,}
但它的验证只能连续重复数字。
答案 0 :(得分:4)
我不建议使用正则表达式来做这样的事情,因为将密码收集到Map
更容易,其中每个字符的计数都保持不变。然后,您可以检查是否存在任何数量超过3
的字符:
password.chars()
.boxed()
.collect(Collectors.groupingBy(i -> i, Collectors.counting()))
.values()
.stream()
.anyMatch(i -> i > 3);
如果true
中的某个字符显示的时间超过password
次,则会返回3
,否则会返回false
。
答案 1 :(得分:2)
使用带有反向引用的负面预测的正则表达式:
boolean ok = str.matches("((.)(?!(.*\\2){3}))+");
请参阅live demo。
在英语中,这个正则表达式说“每个角色在自身之后不得再出现3次”。
答案 2 :(得分:1)
你可以改用地图吗,
public static void main(String[] args) {
System.out.println(validate("121121"));
System.out.println(validate("121212"));
}
static boolean validate(String s)
{
HashMap<Character, Integer> map = new HashMap<>();
for (Character c : s.toCharArray())
{
if (map.containsKey(c))
{
map.put(c, map.get(c) + 1 );
}
else
{
map.put(c , 1);
}
}
for (Integer count : map.values())
{
if (count > 3)
return false;
}
return true;
}
答案 3 :(得分:1)
这方面的正则表达式解决方案非常低效。请考虑从纯粹的学术兴趣来处理这个答案。
具有4次或更多次相同char的字符串失败的模式是
^(?!.*(.).*\1.*\1.*\1).*
如果您需要精确确定此模式,则可以使用限制性更强的模式替换最后一个.*
。
请参阅regex demo。
这里的主要部分是(?!.*(.).*\1.*\1.*\1)
否定前瞻。它匹配
任何0+字符(如果使用Pattern.DOTALL
,任何字符包括换行符),尽可能多,然后它匹配并捕获(用(.)
)任何字符到组1 ,然后匹配任何0+字符,然后匹配相同的字符3次。如果找到(匹配)模式,则整个字符串匹配失败。
为什么效率低下?该模式在很大程度上依赖于回溯。 .*
将所有字符抓取到字符串的末尾,然后引擎回溯,尝试为后续子模式提供一些文本。您可能会看到backtracking steps here。 .*
越多,模式消耗的资源就越多。
为什么懒惰变体没有更好? ^(?!.*?(.).*?\1.*?\1.*?\1).*
看起来更快一些字符串,如果重复的字符彼此接近并且开始时它会更快字符串。如果它们位于字符串的末尾,则效率会降低。因此,如果前一个正则表达式在77个步骤中与121212
匹配,则当前正则表达式也将采用相同数量的步骤。但是,如果您针对1212124444
进行测试,则会看到惰性变体will fail after 139 steps,而贪婪变体fail after 58 steps。反之亦然,4444121212
会导致懒惰的正则表达式失败,14 steps与211 steps with the greedy variant相比。
在Java中,您可以使用它
s.matches("(?!.*(.).*\\1.*\\1.*\\1)")
或
s.matches("(?!.*?(.).*?\\1.*?\\1.*?\\1)")
在制作中使用Jacob's solution。