用于验证4个不同字符的正则表达式是字符串

时间:2015-05-16 19:55:36

标签: java regex

我想强制执行4个不同的字符。

有效示例:

"1q2w3e4r5t"
"abcd"

无效的例子:

"good"
"1ab1"

模式的想法?

3 个答案:

答案 0 :(得分:3)

您应该考虑使用非正则表达式解决方案。我只写这个答案,为这个问题展示一个更简单的正则表达式解决方案。

初始解决方案

这是一个更简单的正则表达式解决方案,它断言字符串中至少有4个不同的字符:

(.).*?((?!\1).).*?((?!\1|\2).).*?((?!\1|\2|\3).).*

Demo on regex101(PCRE和Java对此正则表达式具有相同的行为)

.*?((?!\1).).*?((?!\1|\2).),...搜索之前未出现的下一个字符,通过检查字符与先前捕获组中捕获的字符不同来实现。< / p>

逻辑上,量词的懒惰/贪婪在这里并不重要。惰性量词.*?用于使搜索从之前未出现的最接近的字符开始,而不是从最远的字符开始。它应该稍微改善匹配情况下的性能,因为减少了回溯。

String.matches()一起使用,它声明整个字符串与正则表达式匹配:

input.matches("(.).*?((?!\\1).).*?((?!\\1|\\2).).*?((?!\\1|\\2|\\3).).*")

改进的解决方案

如果您担心表现:

(.)(?>.*?((?!\1).))(?>.*?((?!\1|\2).))(?>.*?((?!\1|\2|\3).)).*

Demo on regex101

使用String.matches()

input.matches("(.)(?>.*?((?!\\1).))(?>.*?((?!\\1|\\2).))(?>.*?((?!\\1|\\2|\\3).)).*")

(?>pattern)构造一旦退出内部模式,就会阻止回溯到组中。这用于将捕获组“锁定”到每个不同字符的第一个外观,因为即使您在字符串中稍后选择不同的字符,结果也是相同的。

这个正则表达式的行为与从左到右循环的普通程序相同,它会根据一组不同的字符检查当前字符,如果当前字符不在集合中,则将其添加到集合中。

由于这个原因,延迟量词.*?变得很重要,因为它搜索到目前为止尚未出现的最接近的字符。

答案 1 :(得分:1)

您可以像这样计算不同字符的数量:

String s = "abcdefaa";
long numDistinctChars = s.chars().distinct().count()

或者如果不是在Java 8上(我无法想出更好的东西):

Set<Character> set = new HashSet<>();
char[] charArray = s.toCharArray();
for (char c : charArray) {
    set.add(Character.valueOf(c));
}
int numDistinctChars = set.size();

答案 2 :(得分:1)

您可以使用正则表达式来验证这一点,使用负面预测来检查捕获的字母数字字符是否相同4次。

我会说这很难看,但是工作:

String rx = "^(.).*?((?!\\1).).*?((?!\\1|\\2).).*?((?!\\1|\\2|\\3).).*?$"

请参阅demo

IDEONE Demo

String re = "^(.).*?((?!\\1).).*?((?!\\1|\\2).).*?((?!\\1|\\2|\\3).).*?$"; 
// Good
System.out.println("1q2w3e4r5t".matches(re));
System.out.println("goody".matches(re));
System.out.println("gggoooggoofr".matches(re));
// Bad
System.out.println("good".matches(re));
System.out.println("1ab1".matches(re));

输出:

true
true
true
false
false