一个用于匹配XXYYZZ模式的正则表达式

12

我想验证一个字符串,它应该遵循模式XXYYZZ,其中X、Y、Z可以是任何字母a-z、A-Z或0-9。

有效字符串的示例:

RRFFKK
BB7733
WWDDMM
5599AA

无效:

555677
AABBCD

目前我正在使用正则表达式(?<=(.))(?!\\1)来分割字符串,并在迭代生成的数组时检查每个子字符串是否具有长度为2。

String str = "AABBEE";
boolean isValid = checkPattern(str);

public static boolean checkPattern(String str) {
   String splited = str.split("(?<=(.))(?!\\1)");
   for (String s : splited) {
       if (s.length() != 2) {
         return false;
       }
   }
   return true;
}

我想用String#matches替换我的检查方式,并且摆脱循环,但是我想不出一个有效的正则表达式。能否有人帮我在下面的片段中放入someRegex

public static boolean checkPattern(String str) {
    return str.matches(someRegex);
}

1
XYZ可以相同吗?BBAABB是否有效? - Wiktor Stribiżew
不。有效的字符串由三个不同的字符组成。 - nopens
5个回答

11

你可以使用

s.matches("(\\p{Alnum})\\1(?!\\1)(\\p{Alnum})\\2(?!\\1|\\2)(\\p{Alnum})\\3")

请查看正则表达式演示

详细信息

  • \A - 开始位置(在String#matches中是隐含的) - 字符串的开始
  • (\p{Alnum})\1 - 一个字母数字字符(捕获到第1组)和一个紧随其后的相同字符
  • (?!\1) - 下一个字符不能与第1组中的字符相同
  • (\p{Alnum})\2 - 一个字母数字字符(捕获到第2组)和一个紧随其后的相同字符
  • (?!\1|\2) - 下一个字符不能与第1组和第2组中的字符相同
  • (\p{Alnum})\3 - 一个字母数字字符(捕获到第3组)和一个紧随其后的相同字符
  • \z -(在String#matches中是隐含的)- 字符串的结尾。

RegexPlanet测试结果:

输入图像说明


1
看到有详细解释的答案真是太好了。 :) - Lii

6

既然你知道有效模式总是六个字符长,包含三对相等且不同于其他字符的字符,那么一系列简单的显式条件可能比正则表达式更简单:

public static boolean checkPattern(String str) {
   return str.length() == 6 &&
          str.charAt(0) == str.chatAt(1) &&
          str.charAt(2) == str.chatAt(3) &&
          str.charAt(4) == str.chatAt(5) &&
          str.charAt(0) != str.charAt(2) &&
          str.charAt(0) != str.charAt(4) &&
          str.charAt(2) != str.charAt(4);
}

是的,这比使用正则表达式简单得多,但 OP 也指出:“有效字符串由三个不同的字符组成。”(我没有投反对票,但注意到此答案的分数下降了1分) - terrorrussia-keeps-killing
1
@fluffy 很好的发现,谢谢!我错过了那个限制。我已经编辑了我的答案来解决这个问题。 - Mureinik
谢谢。我没有想到这么简单的方法。 - nopens
1
如果你要使用Mureinik的答案,你也可以通过提取所有charAt调用到它们各自的变量(比如说,final char c0 = str.charAt(0);)来优化其可读性,这样做未来会更少出错,并且还会将字符缓存到本地变量中(这也会节省一些时间,虽然对于String来说并不是一个很好的胜利,但是可以与任何其他CharSequence实现一起使用,这些实现可能具有不是_O(1)_的.charAt访问时间,就像String一样)。 - terrorrussia-keeps-killing

6
以下内容是否符合您的需求?

以下翻译是否符合您的要求?

^(([A-Za-z\d])\2(?!.*\2)){3}$

查看在线演示


  • ^ - 开始字符串锚定。
  • (- 打开第一个捕获组。
    • ( - 打开第二个捕获组。
      • [A-Za-z\d] - 任何字母数字字符。
      • ) - 关闭第二个捕获组。
    • \2 - 精确匹配刚刚捕获的内容。
    • (?!.*\2) - 负向前瞻,确保同一字符未在其他地方使用。
    • ) - 关闭第一个捕获组。
  • {3} - 重复上述三次。
  • $ - 结束字符串锚定。

5
你可以将外部分组设为非捕获组,并使用\1,这样做很好++。 - The fourth bird
@TheFourthBird,谢谢。非捕获组对性能有所改善吗? - JvdV
理论上来说,我认为可以少跟踪一个组值。但是数据是一个由6个字符组成的字符串,如果有很大的差异我无法判断。 - The fourth bird
@Thefourthbird 这种简化的尝试行不通(请尝试演示自己),因为删除外部捕获组会使 {3} 仅适用于最后一组括号而不是整个字符对。 - arielf
1
@arielf 我认为它是正确的 https://regex101.com/r/b77xpz/1 - The fourth bird
2
@Thefourthbird,谢谢,你是对的。这样做更简单。 从原始描述中并不明显。记录一下:完整的简化正则表达式如下: ^(?:([A-Za-z\d])\1(?!.*\1)){3}$ - arielf

2

这里有另一种使用正则表达式和流结合的解决方案。

  • 它将模式分成两个字符一组。
  • 保留不同的组。
  • 如果计数为3,则返回true
String[] data = { "AABBBB", "AABBCC", "AAAAAA","AABBAA", "ABC", "AAABCC",
        "RRABBCCC" };
String pat = "(?:\\G(.)\\1)+";
Pattern pattern = Pattern.compile(pat);

for (String str : data) {
    Matcher m = pattern.matcher(str);
    boolean isValid = m.results().map(MatchResult::group).distinct().count() == 3;
    System.out.printf("%8s  ->  %s%n",
            str, isValid ? "Valid" : "Not Valid");
}

打印

  AABBBB  ->  Not Valid
  AABBCC  ->  Valid
  AAAAAA  ->  Not Valid
  AABBAA  ->  Not Valid
     ABC  ->  Not Valid
  AAABCC  ->  Not Valid
RRABBCCC  ->  Not Valid

1
你可以检查一个字符是否与其后面的字符匹配,还可以检查不同字符的数量是否为3演示:
public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(isValidPattern("RRFFKK"));
        System.out.println(isValidPattern("BBAABB"));
        System.out.println(isValidPattern("555677"));
    }

    static boolean isValidPattern(String str) {
        return str.length() == 6 &&                
                str.charAt(0) == str.charAt(1) && 
                str.charAt(2) == str.charAt(3) &&
                str.charAt(4) == str.charAt(5) &&
                str.chars().distinct().count() == 3;
    }
}

输出:

true
false
false

注意: String#chars 自Java-9版本开始可用。


System.out.println(isValidPattern("BBAABB")); 这不应该返回 true 吗?但你的输出结果则表示不是。 - Dev-vruper
2
@Dev-vruper - 我的函数表现正确。OP提到:“有效字符串由三个不同的字符组成。” - Arvind Kumar Avinash
@Dev-vruper - 没问题。有时候会发生这种情况。 - Arvind Kumar Avinash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接