提问者:小点点

Java正则表达式匹配贪婪数据(可选后缀除外)


给定一个字符串

Prefix without commas, remainder with optional suffix (optional suffix)

在一次过程中匹配和提取字符串的3个部分的最佳Java正则表达式是什么?

  1. 第一个逗号之前的前缀
  2. 左括号内的剩余部分
  3. 括号内的后缀

对于上面的示例,3个组(在引号内)将是

  1. “不带逗号的前缀”
  2. “带可选后缀的余数”
  3. “(可选后缀)”

字符串的所有3个部分都是可变长度的。余数部分本身可以包含逗号和括号,可选后缀可以以空格开始,也可以不以空格开始,然后是左括号,后面是零个或多个字符,后面是右括号,后面是可选空格,后面是行尾。

试着像

([^,]*),(.*)(\s*\(.*\))?

只产生第1组和第2组,将第3组置于第2组的末尾。


共3个答案

匿名用户

([^,]*),(.*)(\s*\(.*\))?

失败的原因是正则表达式已经成功地执行了([^,]*),(.*),并且不需要检查(回溯)其余部分。

要使其正常工作,请按以下方式更改它(可能有几个选项),这些选项要么不匹配最后一个括号,要么将匹配最后一个括号:

^([^,]*),(.*[^\) ]\s*$) | ([^,]*),(.*)(\s*\(.*\))\s*$

结果($1$3$2$4应合并,$1$2,如果没有可选前缀):

3: Prefix without commas
4:  remainder with optional suffix 
5: (optional suffix)

这里我假设您的可选后缀可以出现多次。阅读问题的另一种方式是希望中间部分重复,即$3包含在$2中。您可以按如下方式执行此操作:

^([^,]*),(.*(?:[^\) ]\s*$ | (\s*\(.*\)\s*$)))

结果:

1: Prefix without commas
2:  remainder with optional suffix (optional suffix)  
3: (optional suffix)  

编辑:在正则表达式上面更新,以允许在结束括号后的空白(这很微妙,您需要将空间添加到负字符类),并锚定正则表达式以加速和减少回溯

匿名用户

以下正则表达式:

^([^,]*),(.*?)(?:\(([^()]*)\))?\s*$

在组2中使用惰性量词,以确保如果有括号,则组3将匹配。另一方面,组3不允许嵌套的paren,以强制仅在字符串的最后一组paren中进行匹配。

代码:

String text = "String prefix without commas, variable length ())(remainde()r with )optional (suffix (optional suffix)";
Pattern regex = Pattern.compile("^([^,]*),(.*?)(?:[(]([^()]*)[)])?\\s*$");
Matcher m = regex.matcher(text);
if (m.find()) {
    System.out.println("1: " + m.group(1));
    System.out.println("2: " + m.group(2));
    System.out.println("3: " + m.group(3));
}

输出:

1: String prefix without commas
2:  variable length ())(remainde()r with )optional (suffix 
3: optional suffix

演示

匿名用户

您可以使用以下正则表达式:

"^([^,]*),([^()]*)(\\s*\\(.*\\))?$"

正则表达式匹配:

  • ^-字符串的开头
  • ([^,]*)-(第1组)0个或更多字符,而不是
  • -文字
  • ([^()]*)-(第2组)0个或更多字符,而不是
  • (\\s*\\(.\\)-(组3)可选组(由于量词表示前面子模式出现1次或0次):
    • \\s*-0或更多空白
    • \\(.\\)-文字然后尽可能多的字符,而不是换行符,直到最后一个

    查看IDEONE演示

    String str = "String prefix without commas, variable length remainder with optional suffix (optional suffix)";
    Pattern ptrn = Pattern.compile("^([^,]*),([^()]*)(\\s*\\(.*\\))?$");
    Matcher matcher = ptrn.matcher(str);
    while (matcher.find()) {
        System.out.println("First group: " + matcher.group(1)
                      + "\nSecond group: " + matcher.group(1) 
                      + (matcher.group(3) != null ? 
                           "\nThrid group: " + matcher.group(3) : ""));