正则表达式从一部分语音解析树中提取名词短语?

时间:2016-03-08 22:14:16

标签: ruby regex nlp

我试图从斯坦福POS解析树中提取所有三个单词的名词短语。基本上,任何看起来像:

(NP (TAG WORD) (TAG WORD) (TAG WORD))

或者:

(NP (TAG WORD) (TAG (TAG WORD) (TAG WORD)))

这就是解析树的样子:

(ROOT (SQ (VBZ Is) (NP (DT this)) (NP (DT an) (NN asthma) (NN attack)) (. ?)))

当我执行此正则表达式时,它会提取正确的3个单词名词短语:

threeWordNounPhrases = full.scan(/\(NP \([^()]+ [^()]+\) \([^()]+ [^()]+\)\)/)
# => "(NP (DT an) (NN asthma) (NN attack))"

但是,这不适用于:

(ROOT (SQ (NNP Should) (NP (PRP I)) (VP (VB watch) (NP (NP (NNP Game)) (PP (IN of) (NP (NNP Thrones)))) ) (. ?)))

应返回:

(NP (NP (NNP Game)) (PP (IN of) (NP (NNP Thrones))))

2 个答案:

答案 0 :(得分:2)

特别是对于三个单词,它是可能的,但不是很漂亮。对于N个单词,正则表达式的复杂性上升。请注意,这只是为了好玩(和regexp / Oniguruma教育);实际上,我建议跟其他人说的一样:使用树解析库并操纵树。

str = "(ROOT (SQ (NNP Should) (NP (PRP I)) (VP (VB watch) (NP (NP (NNP Game)) (PP (IN of) (NP (NNP Thrones)))) ) (. ?)))"

re = /
  (?<tag>
    [A-Z]+
  ){0}

  (?<word>
    \( \g<tag> \s
    (?:
      [^()]+ |
      \g<word>
    )
    \)
  ){0}

  (?<word2>
    \g<word> \s \g<word> |
    \( \g<tag> \s \g<word2> \)
  ){0}

  (?<word3>
    \g<word> \s \g<word> \s \g<word> |
    \g<word2> \s \g<word> |
    \g<word> \s \g<word2> |
    \( \g<tag> \s \g<word3> \)
  ){0}
  \( NP \s \g<word3> \)
/x;

puts str[re]
# => (NP (NP (NNP Game)) (PP (IN of) (NP (NNP Thrones))))

答案 1 :(得分:0)

我没有看到使用正则表达式的方法,除非能够考虑所有可能的结构。你做了什么适用于简单的情况,但正如你所发现的那样,它失败了更深层的嵌套结构。我看到两个选择:

  1. 从文本中遇到(NP的位置开始,请阅读其他字符。保持括号的运行记录。当您看到(时添加到它,当您看到)时减去。当你达到零时,你已经到了NP的末尾。

  2. 使用rubytree解析树。提取由标签为NP的节点支配的所有子树。通过连接叶节点将子树转换回字符串形式。