小编典典

正则表达式精确匹配n个字母出现和m个数字出现

java

我必须匹配一个8字符串,该字符串可以包含正好2个字母(1个大写字母和1个小写字母)以及正好6个数字,但是它们可以任意排列。

因此,基本上:

  • K82v6686将通过
  • 3w28E020会通过
  • 1276eQ900会失败(时间太长)
  • 98Y78k9k会失败(三个字母)
  • A09B2197将会失败(两个大写字母)

我尝试使用正向前瞻来确保该字符串包含数字,大写和小写字母,但是在将其限制为一定数目的出现时遇到了麻烦。我想我可以通过包括字母和数字可能出现的位置的所有可能组合来解决这个问题:

(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z]) ([A-Z][a-z][0-9]{6})|([A-Z][0-9][a-z][0-9]{5})| ... | ([0-9]{6}[a-z][A-Z])

但这是一种非常round回的方式,我想知道是否有更好的解决方案。


阅读 826

收藏
2020-11-16

共1个答案

小编典典

您可以使用

^(?=[^A-Z]*[A-Z][^A-Z]*$)(?=[^a-z]*[a-z][^a-z]*$)(?=(?:\D*\d){6}\D*$)[a-zA-Z0-9]{8}$

参见regex演示(由于多行输入而有些修改)。在Java中,不要忘记使用双反斜杠(例如\\d,匹配一个数字)。

这是一个细分:

  • ^ -字符串的开头(假设不使用多行标志)
  • (?=[^A-Z]*[A-Z][^A-Z]*$)-检查是否只有1个大写字母(用于\p{Lu}匹配任何Unicode大写字母和\P{Lu}其他字符)
  • (?=[^a-z]*[a-z][^a-z]*$)-类似检查是否只有1个小写字母(或者使用\p{Ll}\P{Ll}匹配Unicode字母)
  • (?=(?:\D*\d){6}\D*$)-检查字符串中是否有六个数字(=从字符串的开头开始,可以有0个或多个非数字符号(\D匹配除数字以外的任何字符,也可以将其替换为[^0-9]),然后再跟一个数字(\d),然后是0或多个非数字字符(\D*),直到字符串($)的末尾,然后
  • [a-zA-Z0-9]{8} -精确匹配8个字母数字字符。
  • $ -字符串结尾。

按照逻辑,我们甚至可以将其简化为

^(?=[^a-z]*[a-z][^a-z]*$)(?=(?:\D*\d){6}\D*$)[a-zA-Z0-9]{8}$

可以删除一个条件,因为我们只允许使用大小写字母和数字[a-zA-Z0-9],并且当我们应用2个条件时, 匹配
字符串时会自动执行第三个条件(在这种情况下,一个字符必须为大写)。

当将它与Java matches()方法一起使用时^,无需$在模式的开头和结尾处使用和定位符,但是在前瞻中仍然需要它:

String s = "K82v6686";
String rx = "(?=[^a-z]*[a-z][^a-z]*$)" +      // 1 lowercase letter check
            "(?=(?:\\D*\\d){6}\\D*$)" +       // 6 digits check
            "[a-zA-Z0-9]{8}";                 // matching 8 alphanum chars exactly
if (s.matches(rx)) {
    System.out.println("Valid"); 
}
2020-11-16