关于Java的正则表达式:避免Matcher类不必要的“贪婪”策略

时间:2012-11-07 05:22:37

标签: java regex matcher greedy

我正在尝试开发一个正则表达式来查找字符串中的一系列标记。例如,我可以将标记(NP .*)至少一次(可以多次),然后是标点符号(在本例中为./.)。如果de (NP)./.之间有另一个标记(如下例中的VP),则匹配器不能找到任何内容。问题是,即使我在.*之后使用问号,它也会继续寻找使表达式与字符串中的某些内容匹配的)。这是我的方法:

public void myMethod() {
    String input = "(NP first tag) (VP second tag) ./.";
    String regex = "(\\(NP .*?\\)( )?)+" + "\\./\\.";

    Pattern pattern = Pattern.compile("(" + regex + ")");
    Matcher matcher = pattern.matcher(input);

    if (matcher.find()) {
        System.out.println("<S "+matcher.group(0)+">");
    } else {
        System.out.println("sem grupos.");
    }
}

该方法仍将匹配正则表达式,但不应该。我需要它告诉我没有找到任何组,因为“VP”标签不应该在那里。我认为问题依赖于正则表达式在Java中采用的贪婪策略。它试图找到一些符合正则表达式描述的模式的字符组合。我不知道如何重写这个表达式。

任何帮助?

编辑:

1)我注意到我的问题有点令人困惑,所以我改变了一些例子以使其更清晰。

2)谢谢Aan Moore。我同意我使用的组不是必要的,但这是因为像+这样的运营商。我试图削减不必要的群体。您将.*?替换为[^)]*?的简单想法也很棒!我调整的唯一一件事是我使用)转义了[^\\)]*?符号。下面我展示了最终使用的REGEX。

String regex = "(\\(NP [^\\)]*?\\) ?)+\\./\\.";

非常感谢! :)

1 个答案:

答案 0 :(得分:1)

((\(NP .*?\)( )?)+\./\.)是已编译的模式。

简化:

\(NP .*?\) ?+\./\.删除未使用的捕获组。

现在,让我们看一下您拥有的示例字符串:

(NP first tag) (VP second tag) ./.中,.*?匹配first tag) (VP second tag(NP first tag) (VP second tag) (MISC tag that must not be catch) ./..*?匹配first tag) (VP second tag) (MISC tag that must not be catch

为什么呢?我的意思是,这不是非贪心的吗?对,但是......

.*?\)开始匹配first tag),你想要什么。然而,正则表达式的其余部分未能通过匹配,正则表达式引擎会将其作为可能的答案抛出并继续查看。

如果您没有像(NP(tag))这样的标签中的标签,您可以更改模式:\(NP [^)]*?\)

要匹配您在问题中描述的字符串:\(NP [^)]*?\) ?\(VP [^)]*?\) \./\.

随着Java转义,它变为\\(NP [^)]*?\\) ?\\(VP [^)]*?\\) \./\.

为了进一步阅读,有一个很好的Stack Overflow question涵盖了更多的理论和实践。