我正在使用带有Unicode字符的非英语解析器。为此,我决定使用NLTK。
但它需要一个预定义的无上下文语法,如下所示:
S -> NP VP
VP -> V NP | V NP PP
PP -> P NP
V -> "saw" | "ate" | "walked"
NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
Det -> "a" | "an" | "the" | "my"
N -> "man" | "dog" | "cat" | "telescope" | "park"
P -> "in" | "on" | "by" | "with"
在我的应用程序中,我应该使用基于规则的语法来最小化硬编码。 例如,我可以假设以 -ed 或 -ing 结尾的任何单词作为动词。所以它应该适用于任何给定的上下文。
如何将此类语法规则提供给NLTK?或者使用有限状态机动态生成它们?
答案 0 :(得分:7)
如果你正在创建一个解析器,那么<strong>有在实际解析之前添加一个pos-tagging步骤 - 没有办法成功确定一个单词的POS-tag上下文。例如,'封闭'可以是形容词或动词; POS标签可以从单词的上下文中找到适合您的标签。然后,您可以使用POS标记器的输出来创建CFG。
您可以使用众多现有POS标签之一。在NLTK中,您可以简单地执行以下操作:
import nltk
input_sentence = "Dogs chase cats"
text = nltk.word_tokenize(input_sentence)
list_of_tokens = nltk.pos_tag(text)
print list_of_tokens
输出将是:
[('Dogs', 'NN'), ('chase', 'VB'), ('cats', 'NN')]
您可以使用它来创建语法字符串并将其提供给nltk.parse_cfg()
。
答案 1 :(得分:2)
也许您正在寻找CFG.fromstring()
(以前为parse_cfg()
)?
来自NLTK书籍的Chapter 7(更新为NLTK 3.0):
> grammar = nltk.CFG.fromstring("""
S -> NP VP
VP -> V NP | V NP PP
V -> "saw" | "ate"
NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
Det -> "a" | "an" | "the" | "my"
N -> "dog" | "cat" | "cookie" | "park"
PP -> P NP
P -> "in" | "on" | "by" | "with"
""")
> sent = "Mary saw Bob".split()
> rd_parser = nltk.RecursiveDescentParser(grammar)
> for p in rd_parser.parse(sent):
print p
(S (NP Mary) (VP (V saw) (NP Bob)))
答案 2 :(得分:1)
您可以使用具有正则表达能力决定令牌的NLTK RegexTagger 。这正是您需要的。作为令牌结尾的标记&#39;将被标记为动名词和令牌以“&#39; ed”结尾。将用动词过去标记。见下面的例子。
patterns = [
(r'.*ing$', 'VBG'), # gerunds
(r'.*ed$', 'VBD'), # simple past
(r'.*es$', 'VBZ'), # 3rd singular present
(r'.*ould$', 'MD'), # modals
(r'.*\'s$', 'NN$'), # possessive nouns
(r'.*s$', 'NNS') # plural nouns
]
请注意,这些按顺序处理,并应用匹配的第一个。现在 我们可以设置一个标记器并用它来标记一个句子。在这一步之后,关于a是正确的 五分之一。
regexp_tagger = nltk.RegexpTagger(patterns)
regexp_tagger.tag(your_sent)
您可以使用组合标记在序列中共同使用多个标记。
答案 3 :(得分:0)
你现在不能在nltk中编写这样的规则而不需要任何努力,但你可以制定一些技巧。
例如,在某些单词信息标签中转录您的句子并相应地写出您的语法规则。
例如(使用POS标签作为标签):
Dogs eat bones.
变为:
NN V NN.
语法终端规则示例:
V -> 'V'
如果这还不够,你应该考虑更灵活的形式主义实施。
答案 4 :(得分:0)
另一种选择是使用正则表达式解析器。见https://www.nltk.org/book/ch07.html。像这样:
>>> import nltk, re, pprint
>>> from nltk import word_tokenize, sent_tokenize
>>> my_sentence = "This is just an example"
>>> tokenized_sentence = word_tokenize(my_sentence)
>>> tagged_sentence = nltk.pos_tag(tokenized_sentence)
>>> grammar = """
... P: {<IN>}
... N: {<NN.*>}
... DET: {<DT>}
... NP: {<DET><N><PP>?}
... {<NNP>}
... V: {<VB.*>}
... PP: {<P><NP>}
... VP: {<V><NP>}
... {<V><NP><PP>}
... S: {<NP><VP>}
... """
>>> cp = nltk.RegexpParser(grammar)
>>> tree = cp.parse(tagged_sentence)
>>> print(tree)
(S (DET This/DT) (V is/VBZ) just/RB (NP (DET an/DT) (N example/NN)))
缺点是,如果您正在寻找特定的硬编码词,这不会直接告诉您。但是,您可以使用类似的方法处理树并找出单词。上面链接中的书对此进行了描述。
for subtree in tree.subtrees():
if subtree.label() == 'N':
noun = subtree[0][0]
do_something(noun)