我正在尝试从斯坦福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))))
具体来说,三个词是可能的,但并不漂亮。对于 N 个单词,正则表达式的复杂性增加。请注意,这只是为了好玩(和正则表达式/鬼谷子教育);实际上,我建议遵循其他人所说的:使用树解析库并操纵树。
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))))
除非能够考虑所有可能的结构,否则我看不到使用正则表达式的方法。您所做的适用于简单情况,但正如您发现的那样,它因更深的嵌套结构而失败。我看到两个选项:
-
从您在文本中遇到
(NP
的地方开始,阅读其他字符。保持括号的连续计数。看到(
时加,看到)
减去。当你达到零时,你已经到达了NP
的尽头。 -
使用 rubytree 解析树。提取由标签为
NP
的节点主导的所有子树。通过连接叶节点将子树转换回字符串形式。