如何在特定行上获取多个Java正则表达式匹配

4

我正在调用一个API,但我无法更改它。也就是说,我不能像使用两个顺序的正则表达式或其他任何方式来处理。该API的代码类似于以下内容(当然是简化过的):

void apiMethod(final String regex) {
    final String input = 
        "bad:    thing01, thing02, thing03 \n" +
        "good:   thing04, thing05, thing06 \n" +
        "better: thing07, thing08, thing09 \n" +
        "worse:  thing10, thing11, thing12 \n";

    final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);

    final Matcher matcher = pattern.matcher(input);

    while (matcher.find()) {
        System.out.println(matcher.group(1));
    }
}

我会这样调用它:

apiMethod("(thing[0-9]+)");

我希望看到六行输出,每一行对应04至09中的一项。但是我迄今为止没有成功。以下是我尝试过但未成功的一些方法:
  • "(thing[0-9]+)" - 这匹配了所有12个事物,这不是我想要的。
  • "^(?:good|better): (thing[0-9]+)" - 这只匹配了4和7两个事物。
  • "^(?:(?:good|better): .*)(thing[0-9]+)" - 这只匹配了6和9两个事物。
  • "(?:(?:^good:|^better:|,) *)(thing[0-9]+)" - 这匹配了除1和10之外的所有内容。

还有很多其他的方法,太多了无法一一列举。我尝试了各种前瞻,但都没有成功。

我想要的是所有与"thing[0-9]+"匹配的字符串,但仅限于以"good:"或"better:"开头的行。

更一般地说,我想从多行模式中获取多个匹配项,但仅限于具有特定前缀的行。


(^(?:好|更好):*thing\d{2}.*) - CAustin
1
这将仅匹配第一组,而不是行中的所有内容。 - 11thdimension
他说他想要多个匹配,这正是该模式所做的。你可以用非常相似的东西 ((?:^(?:good|better): *thing\d{2}.*\n)+) 一次性获取所有内容。 - CAustin
1个回答

5

你需要使用基于 \G 的模式(在多行模式下):

(?:\G(?!^),|^(?:good|better):)\s*(thing[0-9]+)
\G锚定符强制匹配连续,因为它匹配上一次成功匹配后的位置。
如果行比较短,您还可以使用有限的变长回溯来实现这一点。
(?<=^(?:good|better):.{0,1000})(thing[0-9]+)

今天我学到了关于\G锚点的知识。非常感谢!顺便问一下,(?!^)是什么意思?我知道它是用于匹配行首的负向先行断言,但为什么需要它呢? - Matt Malone
正则表达式不错,但是你不需要使用负向前瞻来匹配开头 (?!^),因为行首从来不会以逗号开头。也就是说,这个可以工作:"(?:\\G,|^(?:good|better):)\\s*(thing\\d+)" - Bohemian
@Matt 不需要。请看我的评论。 - Bohemian
1
@MattMalone: 因为\G也会匹配字符串的开头。添加(?!^)可以避免这种情况,但是如果您没有以逗号开头的行,则可以将其删除。 - Casimir et Hippolyte

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