正则表达式在Java中匹配未转义的逗号

Regex matching unescaped commas in Java

问题描述

我正试图使用String类提供的split()方法将a拆分为单独的字符串。文档告诉我它将围绕参数的匹配项进行拆分,这是一个正则表达式。我使用的分隔符是逗号,但逗号也可以转义。我使用的逃逸字符是一个前斜杠/(只是为了不使用反斜杠来使事情变得更容易,因为这需要在Java和正则表达式中的字符串文本中附加的逃逸)。

例如,输入可能是:

1
a,b/,b//,c///,//,d///,

输出应为:

1
2
3
4
a
b,b/
c/,/
d/,

所以,字符串应该在每个逗号处拆分,除非逗号前面有奇数个斜杠(1,3,5,7,…,∞),因为这意味着逗号被转义了。

可能的解决方案

我最初的猜测是这样拆分它:

1
String[] strings = longString.split("(?<![^/](//)*/),");

但这是不允许的,因为Java不允许在组后面进行无限的查看。我可以通过用02000替换*将复发率限制在2000年:

1
String[] strings = longString.split("(?<![^/](//){0,2000}/),");

但这仍然对输入施加了限制。所以我决定从"幕后观察"组中剔除这种复发,并得出了以下结论:

1
String[] strings = longString.split("(?<!/)(?:(//)*),");

但是,它的输出是以下字符串列表:

1
2
3
4
a
b,b (the final slash is lacking in the output)
c/, (the final slash is lacking in the output)
d/,

为什么那些斜线在第二和第三弦中被省略,我怎样才能解决它(在爪哇)?


您可以使用逗号前面的偶数个斜杠的正查找来实现拆分:

1
String[] strings = longString.split("(?<=[^/](//){0,999999999}),");

但要显示所需的输出,需要进一步删除其余转义:

1
2
3
4
String longString ="a,b/,b//,c///,//,d///,";
String[] strings = longString.split("(?<=[^/](//){0,999999999}),");
for (String s : strings)
    System.out.println(s.replaceAll("/(.)","$1"));

输出:

1
2
3
4
a
b,b/
c/,/
d/,


你离得很近。要克服查找错误,可以使用以下解决方法:

1
String[] strings = longString.split("(?<![^/](//){0,99}/),")


如果您不介意使用regex的其他方法,我建议使用.matcher

1
2
3
4
5
6
Pattern pattern = Pattern.compile("(?:[^,/]+|/.)+");
String test ="a,b/,b//,c///,//,d///,";
Matcher matcher = pattern.matcher(test);
while (matcher.find()) {
    System.out.println(matcher.group().replaceAll("/(.)","$1"));
}

输出:

1
2
3
4
a
b,b/
c/,/
d/,

Ideone演示

此方法将匹配除分隔逗号(有点相反)之外的所有内容。其优点是它不依赖于观察。


我喜欢regex,但是在这里手动编写代码不是很容易吗,也就是说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
boolean escaped = false;
for(int i = 0, len = s.length() ; i < len ; i++){
    switch(s.charAt(i)){
    case"/": escaped = !escaped; break;            
    case",":
      if(!escaped){
         //found a segment, do something with it
      }
      //Fallthrough!
    default:
      escaped = false;
    }
}
// handle last segment