Java正则表达式 - 重叠匹配

27
在下面的代码中:
public static void main(String[] args) {
    List<String> allMatches = new ArrayList<String>();
    Matcher m = Pattern.compile("\\d+\\D+\\d+").matcher("2abc3abc4abc5");
    while (m.find()) {
        allMatches.add(m.group());
    }

    String[] res = allMatches.toArray(new String[0]);
    System.out.println(Arrays.toString(res));
}

结果是:

[2abc3, 4abc5]
我希望它变成这样
[2abc3, 3abc4, 4abc5]

如何实现?


您需要从每个索引开始搜索;使用find(int startingIndex)方法并从每个字符位置开始搜索。当然,这样您可能会找到太多的匹配项...假设你想从每个数字开始,你可以尝试将Matcher.find(String.indexOf(digits,index))的迭代组合为所有匹配的索引。 - user1676075
我想如果它是个位数,你可以从匹配的起始位置往回找到下一个匹配。 - user1676075
1
对于输入的字符串 "12abc13abc14abc15", 你想要 [12abc13, 2abc13, 13abc14, 3abc14, 14abc15, 4abc15] 还是 [12abc13, 13abc14, 14abc15] - johnchen902
@johnchen902:后者。解决方案可以处理这个问题。 - Evgeny
3个回答

18

让匹配器尝试从后面的\d+开始下一次扫描。

Matcher m = Pattern.compile("\\d+\\D+(\\d+)").matcher("2abc3abc4abc5");
if (m.find()) {
    do {
        allMatches.add(m.group());
    } while (m.find(m.start(1)));
}

给前两位点赞的用户:普通版本存在一个bug,如果没有匹配项,则会抛出IllegalStateException - johnchen902

16

不确定在Java中是否可能,但是在PCRE中,您可以执行以下操作:
(?=(\d+\D+\d+)).

说明
技巧是在一个前瞻匹配组中使用匹配组,然后“吃掉”一个字符以向前移动。

  • (?= :正向前瞻的开始
    • ( :开始匹配组1
      • \d+ :匹配一个或多个数字
      • \D+ :匹配一个或多个非数字字符
      • \d+ :匹配一个或多个数字
    • ) :结束组1
  • ) :结束前瞻
  • . :匹配任何字符,这是“向前移动”的意思。

在线演示


感谢Casimir et Hippolyte,它似乎真的在Java中有效。 您只需要添加反斜杠并显示第一个捕获组:(?=(\\d+\\D+\\d+)).。 在www.regexplanet.com上测试:

enter image description here


@anubhava:我已经测试过了,它运行良好,假设你添加反斜杠并显示第一个捕获组。downvoter:这里的负分没有意义。 - Casimir et Hippolyte
@anubhava 我知道,但我在这里进行了测试(http://www.regexplanet.com/advanced/java/index.html),它是有效的(http://i.stack.imgur.com/kPa03.png)。 - HamZa
2
并不是完全有效的。使用 12abc13abc14abc15 作为输入,结果应该是 [12abc13, 13abc14, 14abc15],而不是 [12abc13, 2abc13, 13abc14, 3abc14, 14abc15, 4abc15]。请参见我和 OP 在问题下面的评论。 - johnchen902
1
@johnchen902 йҮҚеҸ еҢ№й…ҚпјҒиҝҷе°ұжҳҜд»–дёҖејҖе§ӢжғіиҰҒзҡ„...еҰӮжһңдёҚжҳҜиҝҷз§Қжғ…еҶөпјҢйӮЈд№Ҳ(?=(\d+\D+\d+))\d+еҸҜд»Ҙе®ҢжҲҗд»»еҠЎгҖӮ - HamZa
6
如果你不想在结果中出现重叠的结果,那么你必须将模式替换为(?=((?<!\\d)\\d+\\D+\\d+))。 :) - Casimir et Hippolyte
显示剩余4条评论

4

HamZa提供的解决方案在Java中完美运行。如果您想在文本中查找特定模式,您只需要执行以下操作:

String regex = "\\d+\\D+\\d+";

String updatedRegex = "(?=(" + regex + ")).";

如果你想要重叠的匹配,你需要在正则表达式模式周围加上 (?=(" 在开始处和 ")). 在结尾处。


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