为什么正则表达集团不起作用

时间:2017-03-03 07:41:28

标签: java regex regex-group

我尝试了以下regx(java字符串格式):

^(.*(iOS\\s+[\\d\\.]+|Android\\s+[\\d\\.]+)?.*)$

要匹配的字符串是:

Some Money 2.6.2; iOS 5.1.1 

它假设返回三组:

group[0] :Some Money 2.6.2; iOS 5.1.1
group[1] :Some Money 2.6.2; iOS 5.1.1
group[2] :iOS 5.1.1

但它实际上会返回这些:

group[0] :Some Money 2.6.2; iOS 5.1.1 
group[1] :Some Money 2.6.2; iOS 5.1.1 
group[2] :null

当我改变正则表达式如下

^(.*(iOS\\s+[\\d\\.]+|Android\\s+[\\d\\.]+).*)$

但它不能像

那样匹配字符串
whatever iS 5.1.1 whatever

我想要实现的是正则表达式返回三组,无论字符串是什么。第一组和第二组始终是整个字符串。第三组是匹配'(iOS | Android)[\ d。] *'的子字符串。如果string确实包含该部分,如果它不包含,则为null或为空。

3 个答案:

答案 0 :(得分:2)

也许您可以使用;分隔符作为iOS 5.1.1部分开始的指示?

然后模式可能看起来像.+;\\s+(.+)

  • .+;消耗一切直至分号
  • \\s+使用分号和版本字符串
  • 之间的空格
  • (.+)消耗所有内容直到最后

如果您真的只想匹配 iOS Android ,那么您可能希望在(.+)部分中添加非捕获组。 然后regexp看起来像这样:".+;\\s+((?:iOS|Android).+)"

这里有一个可执行的示例,解决方案可能是什么样子。它显示了我在上面解释的两种模式变体的行为。

public static void main(String[] args) {
    String input1 = "Some Money 2.6.2; iS 5.1.1 ";
    String input2 = "Some Money 2.6.2; iOS 5.1.1 ";
    String input3 = "Some Money 2.6.2; Android 5.1.1 ";

    String pattern1 = ".+;\\s+(.+)";
    String pattern2 = ".+;\\s+((?:iOS|Android).+)";

    System.out.println(pattern1);
    matchPattern(input1, pattern1);
    matchPattern(input2, pattern1);
    matchPattern(input3, pattern1);
    System.out.println();
    System.out.println(pattern2);
    matchPattern(input1, pattern2);
    matchPattern(input2, pattern2);
    matchPattern(input3, pattern2);
}

private static void matchPattern(String input, String pattern) {
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(input);
    if(m.matches()) {
        System.out.println(m.group(0));
        System.out.println(m.group(1));
        if(m.groupCount() > 1) {
            System.out.println(m.group(2));
        }
    }
}

更新:由于作者的某些修改,问题的目标更加清晰,我觉得有必要更新我的答案。如果它总是得到三个组,则以下可能比制定所有可能的符号变体更好:

public static void main(String[] args) {
    String input1 = "Some Money 2.6.2; iS 5.1.1";
    String input2 = "Some Money 2.6.2; iOS 5.1.1";
    String input3 = "Some Money 2.6.2; Android 5.1.1";
    String input4 = "Some Money 2.6.2 iOS 5.1.1";
    String input5 = "Some Money 2.6.2 iOS";
    String input6 = "Some Money 2.6.2";

    String pattern1 = "(.*?((?:iOS|Android)(?:\\s+[0-9\\.]+)?.*)?)";

    System.out.println(pattern1);
    matchPattern(input1, pattern1);
    matchPattern(input2, pattern1);
    matchPattern(input3, pattern1);
    matchPattern(input4, pattern1);
    matchPattern(input5, pattern1);
    matchPattern(input6, pattern1);
}

private static void matchPattern(String input, String pattern) {
    Pattern p = Pattern.compile(pattern);
    Matcher m = p.matcher(input);
    if(m.matches()) {
        System.out.println(m.group(0));
        System.out.println(m.group(1));
        System.out.println(m.group(2));
        System.out.println();
    }
}

此处的模式为(.*?(?:((?:iOS|Android)(?:\\s+[0-9\\.]+)?).*)?)

  • .*?会占用版本字符串之前的所有内容。如果没有可用的版本字符串,则它匹配整个输入。 此处需要Reluctant quantifier。它需要仍然匹配的最短匹配,因此避免消耗整个输入。
  • (?:((?:iOS|Android)(?:\\s+[0-9\\.]+)?).*)?使用整个版本字符串以及随后的所有内容。
  • ((?:iOS|Android)(?:\\s+[0-9\\.]+)?)组(2)输出。它只是匹配操作系统字符串 iOS Android ,带有由数字和点组成的可选版本后缀。

答案 1 :(得分:0)

请参考this topic关于" RegEx引擎如何运作"。

  
      
  1. 基于反向跟踪的。这些通常将模式编译成字节码,类似于机器指令。然后引擎执行代码,从指令跳转到指令。当指令失败时,它会回溯以找到另一种匹配输入的方式。
  2.   

您的正则表达式有很多方法可以匹配输入。可悲的是,它以另一种方式返回(不是你预期的匹配)。

删除"?"来自第二组的量词,它变为" required"。 您返回的商品将匹配所有必需的组。

答案 2 :(得分:0)

我终于用正则表达式解决了这个问题,如下所示。

(.*((?:iOS|Android)\\s+[0-9\\.]+).*|.*)