我想根据连词和逗号分割树。例如,当我有VP and VPNP and NPVP, VPNP,NP时,我想分别提取每个VP或NP。我有以下代码:

 List<Tree> subtrees = constituent.subTreeList();

                for (int i = 0; i < subtrees.size(); i++) {
                    String s = "@VP $+ CC $+ @VP";
                    TregexPattern p = TregexPattern.compile(s);
                    TregexMatcher m = p.matcher(subtrees.get(i));
                    while (m.find()) {
                        m.getMatch().pennPrint();
                        Tree foundTree = m.getMatch();
                        System.out.println(m.getMatch());
                    }
                }


但这不适用于以下文本。我的代码有什么问题?

(VP (VP (VB manage) (NP (NP (DT the) (JJ entire) (NN life) (NN cycle)) (PP (IN of) (NP (PRP$ your) (NNS APIs))))) (CC and) (VP (VB expose) (NP (PRP$ your) (NNS APIs)) (PP (TO to) (NP (JJ third-party) (NNS developers)))))

最佳答案

这里的主要问题是链式Tregex关系(遵循tgrep和tgrep2的传统)具有特殊的非关联语义:A r1 B r2 C [r3 D]表示A r1 BA r2 CA r3 D。 (对于A < B < C的核心用例,这通常是有意义的,这意味着A节点具有B和C子代。要进行另一个分组,您需要使用括号。尤其是,您想要的模式是"@VP $+ (CC $+ @VP)"

在关系列表下的Tregex Javadoc中对此进行了记录,但是我意识到这是一个容易犯的错误,特别是因为相对于典型的数学或编程语言表达式而言,语义是非常不标准的。

如@dantiston所述,还有其他一些改进。与常规的正则表达式一样,您应该只在循环外编译一次模式。而且,让Tregex遍历树的节点而不是构造所有子树的完整列表,会比您更好。这是一些很好的示例代码:

Tree t2 = Tree.valueOf("(VP (VP (VB manage) (NP (NP (DT the) (JJ entire) (NN life) (NN cycle)) (PP (IN of) (NP (PRP$ your) (NNS APIs))))) (CC and) (VP (VB expose) (NP (PRP$ your) (NNS APIs)) (PP (TO to) (NP (JJ third-party) (NNS developers)))))");
List<Tree> trees = Collections.singletonList(t2);

String s = "@VP $+ (@CONJP|CC $+ @VP)";
TregexPattern p = TregexPattern.compile(s);
for (Tree t : trees) {
  TregexMatcher m = p.matcher(t);
  while (m.findNextMatchingNode()) {
    Tree foundTree = m.getMatch();
    System.out.println(foundTree);
  }
}

10-06 02:15