我们可以用 XML 来表示许多种语言信息。然而,灵活性是要付出代价的。每次我们增加复杂性,如允许一个元素是可选的或重复的,我们对所有访问这些数据的程序都要做出更多的工作。我们也使它更难以检查数据的有效性,或使用一种 XML 查询语言来查询数据。
因此,使用 XML 来表示语言结构并不能神奇地解决数据建模问题。我们仍然需要解决如何结构化数据,然后用一个模式定义结构,并编写程序读取和写入格式,以及把它转换为其他格式。同样,我们仍然需要遵循一些有关数据规范化的标准原则。这是明智的,可以避免相同信息的重复复制,所以当只有一个副本变化时,不会导致数据不一致。例如,交叉引用表示为`<xref>headword</xref>`将重复存储一些其他词条的核心词,如果在其他位置的字符串的副本被修改,链接就会被打断。信息类型之间存在的依赖关系需要建模,使我们不能创建没有根的元素。例如,如果 sense 的定义不能作为词条独立存在,那么`sense`就要嵌套在`entry`元素中。多对多关系需要从层次结构中抽象出来。例如,如果一个单词可以有很多对应的`senses`,一个`sense`可以有几个对应的单词,而单词和`senses`都必须作为`(word, sense)`对的列表分别枚举。这种复杂的结构甚至可以分割成三个独立的 XML 文件。
因此,使用 XML 来表示语言结构并不能神奇地解决数据建模问题。我们仍然需要解决如何结构化数据,然后用一个模式定义结构,并编写程序读取和写入格式,以及把它转换为其他格式。同样,我们仍然需要遵循一些有关数据规范化的标准原则。这是明智的,可以避免相同信息的重复复制,所以当只有一个副本变化时,不会导致数据不一致。例如,交叉引用表示为`<xref>headword</xref>`将重复存储一些其他词条的核心词,如果在其他位置的字符串的副本被修改,链接就会被打断。信息类型之间存在的依赖关系需要建模,使我们不能创建没有根的元素。例如,如果 sense 的定义不能作为词条独立存在,那么`sense`就要嵌套在`entry`元素中。多对多关系需要从层次结构中抽象出来。例如,如果一个单词可以有很多对应的`senses`,一个`sense`可以有几个对应的单词,而单词和`senses`都必须作为`(word, sense)`对的列表分别枚举。这种复杂的结构甚至可以分割成三个独立的 XML 文件。
正如我们看到的,虽然 XML 提供了一个格式方便和用途广泛的工具,但它不是能解决一切问题的灵丹妙药。
确保你的文件名后缀为`.cfg`,并且字符串`'file:mygrammar.cfg'`中间没有空格符。如果命令`print(tree)`没有产生任何输出,这可能是因为你的句子`sent`并不符合你的语法。在这种情况下,可以将分析器的跟踪设置打开:`rd_parser = nltk.RecursiveDescentParser(grammar1, trace=2)`。你还可以查看当前使用的语法中的产生式,使用命令`for p in grammar1.productions(): print(p)`。
23. ◑ 在本节中,我们说过简单的用术语 N 元组不能描述所有语言学规律。思考下面的句子,尤其是短语`in his turn`的位置。这是基于 N 元组的方法的一个问题吗?
> `What was more, the in his turn somewhat youngish Nikolay Parfenovich also turned out to be the only person in the entire world to acquire a sincere liking to our "discriminated-against" public procurator.` (Dostoevsky: The Brothers Karamazov)
> `What was more, the in his turn somewhat youngish Nikolay Parfenovich also turned out to be the only person in the entire world to acquire a sincere liking to our "discriminated-against" public procurator.` (Dostoevsky: The Brothers Karamazov)
3.1 中的语法包含一个“缺口引进”产生式,即`S[-INV] -> NP S/NP`。为了正确的预填充斜线特征,我们需要为扩展`S`,`VP`和`NP`的产生式中箭头两侧的斜线添加变量值。例如,`VP/?x -> V SBar/?x`是`VP -> V SBar`的斜线版本,也就是说,可以为一个成分的父母`VP`指定斜线值,只要也为孩子`SBar`指定同样的值。最后,`NP/NP ->`允许`NP`上的斜线信息为空字符串。使用 3.1 中的语法,我们可以分析序列`who do you claim that you like`。
3.1 中的语法包含一个“缺口引进”产生式,即`S[-INV] -> NP S/NP`。为了正确的预填充斜线特征,我们需要为扩展`S`,`VP`和`NP`的产生式中箭头两侧的斜线添加变量值。例如,`VP/?x -> V SBar/?x`是`VP -> V SBar`的斜线版本,也就是说,可以为一个成分的父母`VP`指定斜线值,只要也为孩子`SBar`指定同样的值。最后,`NP/NP ->`允许`NP`上的斜线信息为空字符串。使用 3.1 中的语法,我们可以分析序列`who do you claim that you like`。
```py
>>>tokens='who do you claim that you like'.split()
...
...
@@ -611,7 +611,7 @@ Feature Bottom Up Predict Combine Rule: