我必须匹配一个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回的方式,我想知道是否有更好的解决方案。

    最佳答案

    您可以使用

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

    请参见regex demo(由于多行输入而有所修改)。在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()方法一起使用时,无需在模式的开头和结尾使用^$ anchor ,但是在前瞻中仍然需要它:
    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");
    }
    

    10-07 12:59
    查看更多