2017-03-03 70 views
0

我已经试过以下至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 

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

+3

它与第二组不匹配,因为它是可选的,'。*'已经占用了整个字符串。 –

+1

我试图用正则表达式解决问题。现在我有两个问题。 – Joshua

+0

您可以使用['^(*((。?。iOS版| Android版)\ S + \ d] +)*)$'](https://regex101.com/r/OLlDoN/1) – anubhava

回答

2

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

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

  • .+;消耗的一切行动,以分号
  • \\s+消耗分号和版本字符串的开始之间的间隔
  • (.+)消耗一切到最后

如果你真的只想匹配iOSAndroid那么你可能想在内添加一个非捕获组部分。 然后,正则表达式将如下所示:".+;\\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,带有可选的版本后缀由数字和点。
+0

[它似乎没有工作](https://regex101.com/r/3CCnG8/1)为字符串2. –

+0

原因不是,因为正则表达式显式限制为* iOS *和* Android *。我在回答中解释了更一般的方法,而代码使用了更具体的方法,只匹配* iOS *和* Android *。 – Alexander

+0

然后你只需要添加逻辑来返回预期的结果。而且,未锚定的正则表达式会更有效率。 –

0

请参阅this topic关于“RegEx引擎如何工作”。

  • 那些基于回溯跟踪。这些经常将模式编译成字节码,类似于机器指令。然后引擎执行代码,从指令跳转到指令。当一条指令失败时,它会回溯寻找另一种匹配输入的方式。
  • 您的正则表达式有许多方法来匹配输入。可悲的是,它以另一种方式返回(不是你预期的匹配)。

    通过消除 “?”来自第二组的量词,它变成“必需的”。 您返回的maches将匹配所有必需的组。

    0

    我终于通过正则表达式来解决如下问题。

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