Java正则表达式:重复捕获组

31

一个项是由一个或多个数字或字符字符串组成的逗号分隔列表,例如。

"12"
"abc"
"12,abc,3"

我正在尝试在Java中匹配带括号的零个或多个项目列表,例如:

""
"(12)"
"(abc,12)"
"(abc,12),(30,asdf)"
"(qqq,pp),(abc,12),(30,asdf,2),"
应该为最后一个示例返回以下匹配组:
qqq,pp
abc,12
30,asdf,2

我想出了以下(不正确的)模式

\((.+?)\)(?:,\((.+?)\))*

对于最后一个示例,只匹配以下内容

qqq,pp
30,asdf,2

有什么建议吗?谢谢


2
你可以尝试在“),(”处分割字符串,并移除剩余的括号以达到你的结果。 - Jens
一定要使用Matcher.find() - Qix - MONICA WAS MISTREATED
5个回答

45

没错,Java正则表达式中不能有数量不确定的捕获组。你的Pattern只有两个组:

\((.+?)\)(?:,\((.+?)\))*
  |___|        |___|
 group 1      group 2
每个组将包含该组的最后一个匹配项的内容。也就是说,abc,12将被30,asdf,2覆盖。
相关问题: 解决方法是使用一个表达式(类似于\((.+?)\)),然后使用matcher.find迭代匹配项。

啊好的,谢谢。我不知道那个,现在我得想出一个替代方案。 - Justin Wong
1
是的,这肯定很烦人。.net有这个功能(就像我链接的问题/答案中所看到的那样)。 - aioobe
6
@David,如果你错过了,他已经给你一个很好的替代方案 :) - Svish

1
使用ANTLR语法可以解决这个问题。这真的超出了RegExp的合理能力范围,尽管我相信在.Net的某些更新版本中支持这种行为。如果除了.Net之外其他都卡住了,你最好的选择是使用解析器生成器(你不必使用ANTLR,那只是我的个人偏好)。通过ANTLR4 GitHub页面可以帮助初学者开始匹配更复杂的表达式,例如重复匹配组。另一种不需要太多新学习的选择是对你想要匹配的字符串输入进行标记化,并提取出你想要的部分,但这可能会变得非常混乱,创建噩梦般的大块解析代码,更适合使用生成的解析器。

1
你可以在循环中使用正则表达式,例如([^,]+),或者只需使用str.split(",")一次性获取所有元素。这个版本:str.split("\\s*,\\s*")甚至允许空格。

1

(^|\s+)(\S*)(($|\s+)\2)+,带有忽略大小写选项 /i

她现在离开了LEft leFT

示例 - https://regex101.com/r/FEmXui/2

Match 1
Full match  3-23    ` left LEft leFT LEFT`
Group 1.    3-4 ` `
Group 2.    4-8 `left`
Group 3.    18-23   ` LEFT`
Group 4.    18-19   ` `

-1

这可能是解决方案:

package com.drl.fw.sch;

import java.util.regex.Pattern;

public class AngularJSMatcher extends SimpleStringMatcher  {

Matcher delegate;


public AngularJSMatcher(String lookFor){
    super(lookFor);
    // ng-repeat 
    int ind = lookFor.indexOf('-');
    if(ind >= 0 ){
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String s : lookFor.split("-")){
            if(first){
                sb.append(s);
                first = false;
            }else{
                if(s.length() >1){
                    sb.append(s.substring(0,1).toUpperCase());
                    sb.append(s.substring(1));

                }else{
                    sb.append(s.toUpperCase());
                }
            }
        }
        delegate = new SimpleStringMatcher(sb.toString());
    }else {
        String words[] = lookFor.split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])");
        if(words.length > 1 ){
            StringBuilder sb = new StringBuilder();
            for (int i=0;i < words.length;i++) {
                sb.append(words[i].toLowerCase());
                if(i < words.length-1) sb.append("-");
            }
            delegate = new SimpleStringMatcher(sb.toString());
        }

    }

}

@Override
public boolean match(String in) {
    if(super.match(in)) return true;
    if(delegate != null && delegate.match(in)) return true;

    return false;
}

public static void main(String[] args){
    String lookfor="ngRepeatStart";

    Matcher matcher = new AngularJSMatcher(lookfor);

    System.out.println(matcher.match( "<header ng-repeat-start=\"item in items\">"));
    System.out.println(matcher.match( "var ngRepeatStart=\"item in items\">"));

}

}


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