diff --git a/0.md b/0.md index 71d88ef118ddf4c0a2dd87265bad0dab95592a01..d1885215a2561d3fc22d8152a9483484458ca7e9 100644 --- a/0.md +++ b/0.md @@ -33,7 +33,7 @@ NLTK 自带大量文档。作为本书的补充,`http://nltk.org/`网站提供 ## Python 3 和 NLTK 3 -本书的这个版本已更新并支持 Python 3 和 NLTK 3。Python 3 包括一些重大的变化︰ +本书的这个版本已更新并支持 Python 3 和 NLTK 3。Python 3 包括一些重大的变化: * `print`语句现在是函数,因此需要括号; * 许多函数现在返回迭代器而不是列表 (以节省内存使用); @@ -43,7 +43,7 @@ NLTK 自带大量文档。作为本书的补充,`http://nltk.org/`网站提供 这些变化的更多细节请参见`https://docs.python.org/dev/whatsnew/3.0.html`.。有一个`2to3.py`工具可以将 Python 2 代码转换为 Python 3;关详细信息请参阅`https://docs.python.org/2/library/2to3.html`。 -NLTK 同样很多地方都有更改︰ +NLTK 同样很多地方都有更改: * 许多类型使用`fromstring()`方法从字符串初始化 * 许多函数现在返回迭代器而不是列表 @@ -63,7 +63,7 @@ NLTK 同样很多地方都有更改︰ | NLTK-Data: | 包含本书中分析和处理的语言语料库。 | | NumPy: | (推荐)这是一个科学计算库,支持多维数组和线性代数,在某些计算概率、标记、聚类和分类任务中用到。 | | Matplotlib: | (推荐)这是一个用于数据可视化的 2D 绘图库,本书在产生线图和条形图的程序例子中用到。 | -| 斯坦福大学 NLP 工具︰ | (推荐)NLTK 包括斯坦福大学 NLP 工具的接口,可用于大型语言处理(见`http://nlp.stanford.edu/software/`)。 | +| 斯坦福大学 NLP 工具: | (推荐)NLTK 包括斯坦福大学 NLP 工具的接口,可用于大型语言处理(见`http://nlp.stanford.edu/software/`)。 | | NetworkX: | (可选)这是一个用于存储和操作由节点和边组成的网络结构的函数库。可视化语义网络还需要安装 *Graphviz* 库。 | | Prover9: | (可选)这是一个使用一阶等式逻辑定理的自动证明器,用于支持语言处理中的推理。 | @@ -92,11 +92,11 @@ NLTK 创建于 2001 年,最初是宾州大学计算机与信息科学系计算 NLTK 设计中的四个主要目标: -| 简单︰ | 提供一个直观的框架和大量构建模块,使用户获取 NLP 知识而不必陷入像标注语言数据那样繁琐的事务中 | +| 简单: | 提供一个直观的框架和大量构建模块,使用户获取 NLP 知识而不必陷入像标注语言数据那样繁琐的事务中 | | --- | --- | -| 一致︰ | 提供一个具有一致的接口和数据结构的,并且方法名称容易被猜到的统一的框架 | -| 可扩展︰ | 提供一种结构,新的软件模块包括同一个任务中的不同的实现和相互冲突的方法都可以方便添加进来 | -| 模块化︰ | 提供的组件可以独立使用而无需理解工具包的其他部分 | +| 一致: | 提供一个具有一致的接口和数据结构的,并且方法名称容易被猜到的统一的框架 | +| 可扩展: | 提供一种结构,新的软件模块包括同一个任务中的不同的实现和相互冲突的方法都可以方便添加进来 | +| 模块化: | 提供的组件可以独立使用而无需理解工具包的其他部分 | 对比上述目标,我们有意回避了工具包三个非需求行的但可能有用的特征。首先,虽然工具包提供了广泛的工具,但它不是面面俱全的;它是一个工具包而不是一个系统,它将会随着 NLP 领域一起演化。第二,虽然这个工具包的效率足以支持实际的任务,但它运行时的性能还没有高度优化;这种优化往往涉及更复杂的算法或使用 C 或 C++ 等较低一级的编程语言来实现。这将影响工具包的可读性且更难以安装。第三,我们试图避开巧妙的编程技巧,因为我们相信清楚直白的实现比巧妙却可读性差的方法好。 diff --git a/1.md b/1.md index 1de63176eb912d654b21a511d5d0ce591d3ac98a..59a53955fa11c7592eeb9caf1a77831a069150c2 100644 --- a/1.md +++ b/1.md @@ -26,7 +26,7 @@ Type "help", "copyright", "credits" or "license" for more information. 注 -如果你无法运行 Python 解释器可能是因为没有正确安装 Python。请访问`http://python.org/`查阅详细操作说明。NLTK 3.0 在 Python 2.6 和 2.7 上同样可以工作。如果你使用的是这些较旧的版本,注意`/`运算符会向下舍入小数(所以`1/3`会得到`0`)。为了得到预期的除法行为,你需要输入︰`from __future__ import division` +如果你无法运行 Python 解释器可能是因为没有正确安装 Python。请访问`http://python.org/`查阅详细操作说明。NLTK 3.0 在 Python 2.6 和 2.7 上同样可以工作。如果你使用的是这些较旧的版本,注意`/`运算符会向下舍入小数(所以`1/3`会得到`0`)。为了得到预期的除法行为,你需要输入:`from __future__ import division` `>>>`提示符表示 Python 解释器正在等待输入。复制这本书的例子时,自己不要键入"`>>>`"。现在,让我们开始把 Python 当作计算器使用: @@ -832,7 +832,7 @@ word length is less than 5 注意 -如果你正在使用 Python 2.6 或 2.7,为了识别上面的`print`函数,需要包括以下行︰ +如果你正在使用 Python 2.6 或 2.7,为了识别上面的`print`函数,需要包括以下行: ```py >>> from __future__ import print_function diff --git a/2.md b/2.md index 3abd6e7206b7175d195dccd4b4218ed52050591e..8d0afa6051218ff0e57eb4d0790baca1cce72046 100644 --- a/2.md +++ b/2.md @@ -499,7 +499,7 @@ German_Deutsch 0 171 263 614 717 894 1013 1110 1213 1275 ## 2.4 使用双连词生成随机文本 -我们可以使用条件频率分布创建一个双连词表(词对)。(我们在 3 中介绍过。)`bigrams()`函数接受一个单词列表,并建立一个连续的词对列表。记住,为了能看到结果而不是神秘的"生成器对象",我们需要使用`list()`函数︰ +我们可以使用条件频率分布创建一个双连词表(词对)。(我们在 3 中介绍过。)`bigrams()`函数接受一个单词列表,并建立一个连续的词对列表。记住,为了能看到结果而不是神秘的"生成器对象",我们需要使用`list()`函数: ```py >>> sent = ['In', 'the', 'beginning', 'God', 'created', 'the', 'heaven', diff --git a/3.md b/3.md index 0975098efc1063bca348fe7318811944abff6ad8..ef41c941ee21216dca83bc08b757194d97723a92 100644 --- a/3.md +++ b/3.md @@ -43,7 +43,7 @@ NLTK 语料库集合中有古腾堡项目的一小部分样例文本。然而, 注意 -`read()`过程将需要几秒钟来下载这本大书。如果你使用的 Internet 代理 Python 不能正确检测出来,你可能需要在使用`urlopen`之前用下面的方法手动指定代理: +`read()`过程将需要几秒钟来下载这本大书。如果你使用的互联网代理 Python 不能正确检测出来,你可能需要在使用`urlopen`之前用下面的方法手动指定代理: ```py >>> proxies = {'http': 'http://www.someproxy.com:3128'} @@ -81,7 +81,7 @@ great deal; Nikodim Fomitch; young man; Ilya Petrovitch; n't know; Project Gutenberg; Dmitri Prokofitch; Andrey Semyonovitch; Hay Market ``` -请注意,Project Gutenberg 以一个搭配出现。这是因为从古腾堡项目下载的每个文本都包含一个首部,里面有文本的名称、作者、扫描和校对文本的人的名字、许可证等信息。有时这些信息出现在文件末尾页脚处。我们不能可靠地检测出文本内容的开始和结束,因此在从`原始`文本中挑出正确内容且没有其它内容之前,我们需要手工检查文件以发现标记内容开始和结尾的独特的字符串: +请注意,`Project Gutenberg`以一个搭配出现。这是因为从古腾堡项目下载的每个文本都包含一个首部,里面有文本的名称、作者、扫描和校对文本的人的名字、许可证等信息。有时这些信息出现在文件末尾页脚处。我们不能可靠地检测出文本内容的开始和结束,因此在从`原始`文本中挑出正确内容且没有其它内容之前,我们需要手工检查文件以发现标记内容开始和结尾的独特的字符串: ```py >>> raw.find("PART I") @@ -93,13 +93,13 @@ Project Gutenberg; Dmitri Prokofitch; Andrey Semyonovitch; Hay Market 0 ``` -方法`find()`和`rfind()`(反向的 find)帮助我们得到字符串切片需要用到的正确的索引值❶。我们用这个切片重新给`raw`赋值,所以现在它以“PART I”开始一直到(但不包括)标记内容结尾的句子。 +方法`find()`和`rfind()`(反向查找)帮助我们得到字符串切片需要用到的正确的索引值❶。我们用这个切片重新给`raw`赋值,所以现在它以`PART I`开始一直到(但不包括)标记内容结尾的句子。 这是我们第一次接触到网络的实际内容:在网络上找到的文本可能含有不必要的内容,并没有一个自动的方法来去除它。但只需要少量的额外工作,我们就可以提取出我们需要的材料。 ### 处理 HTML -网络上的文本大部分是 HTML 文件的形式。你可以使用网络浏览器将网页作为文本保存为本地文件,然后按照下面关于文件的小节描述的那样来访问它。不过,如果你要经常这样做,最简单的办法是直接让 Python 来做这份工作。第一步是像以前一样使用`urlopen`。为了好玩,我们将挑选一个被称为 *Blondes to die out in 200 years* 的 BBC 新闻故事,一个都市传奇被 BBC 作为确立的科学事实流传下来: +网络上的文本大部分是 HTML 文件的形式。你可以使用网络浏览器将网页作为文本保存为本地文件,然后按照下面关于文件的小节描述的那样来访问它。不过,如果你要经常这样做,最简单的办法是直接让 Python 来做这份工作。第一步是像以前一样使用`urlopen`。为了好玩,我们将挑选一个被称为《Blondes to die out in 200 years》的 BBC 新闻故事,一个都市传奇被 BBC 作为确立的科学事实流传下来: ```py >>> url = "http://news.bbc.co.uk/2/hi/health/2284783.stm" @@ -108,9 +108,9 @@ Project Gutenberg; Dmitri Prokofitch; Andrey Semyonovitch; Hay Market '>> from bs4 import BeautifulSoup @@ -140,7 +140,7 @@ des would disappear is if having the gene was a disadvantage and I do not thin 表 3.1: -搭配的谷歌命中次数:absolutely 或 definitely 后面跟着 adore, love, like 或 prefer 的搭配的命中次数。(Liberman, in *LanguageLog*, 2005)。 +搭配的谷歌命中次数:`absolutely`或`definitely`后面跟着`adore`, `love`, `like`或 `prefer`的搭配的命中次数。(Liberman, in *LanguageLog*, 2005)。 ```py >>> import feedparser @@ -176,7 +176,7 @@ des would disappear is if having the gene was a disadvantage and I do not thin 注意 -**轮到你来**:使用文本编辑器创建一个名为`document.txt`的文件,然后输入几行文字,保存为纯文本。如果你使用 IDLE,在 *File* 菜单中选择 *New Window* 命令,在新窗口中输入所需的文本,然后在 IDLE 提供的弹出式对话框中的文件夹内保存文件为`document.txt`。然后在 Python 解释器中使用`f = open('document.txt')`打开这个文件,并使用`print(f.read())`检查其内容。 +**轮到你来**:使用文本编辑器创建一个名为`document.txt`的文件,然后输入几行文字,保存为纯文本。如果你使用 IDLE,在`File`菜单中选择`New Window`命令,在新窗口中输入所需的文本,然后在 IDLE 提供的弹出式对话框中的文件夹内保存文件为`document.txt`。然后在 Python 解释器中使用`f = open('document.txt')`打开这个文件,并使用`print(f.read())`检查其内容。 当你尝试这样做时可能会出各种各样的错误。如果解释器无法找到你的文件,你会看到类似这样的错误: @@ -188,7 +188,7 @@ f = open('document.txt') IOError: [Errno 2] No such file or directory: 'document.txt' ``` -要检查你正试图打开的文件是否在正确的目录中,使用 IDLE *File* 菜单上的 *Open* 命令;另一种方法是在 Python 中检查当前目录: +要检查你正试图打开的文件是否在正确的目录中,使用 IDLE `File`菜单上的`Open`命令;另一种方法是在 Python 中检查当前目录: ```py >>> import os @@ -242,7 +242,7 @@ You typed 8 words. ### NLP 的流程 -3.1 总结了我们在本节涵盖的内容,包括我们在[1.](./ch01.html#chap-introduction).中所看到的建立一个词汇表的过程。(其中一个步骤,规范化,将在 3.6 讨论。) +3.1 总结了我们在本节涵盖的内容,包括我们在第一章中所看到的建立一个词汇表的过程。(其中一个步骤,规范化,将在 3.6 讨论。) ![Images/pipeline1.png](Images/8c5ec1a0132f7c85fd96eda9d9929d15.jpg) @@ -560,11 +560,11 @@ TypeError: object does not support item assignment ## 3.3 使用 Unicode 进行文字处理 -我们的程序经常需要处理不同的语言和不同的字符集。“纯文本”的概念是虚构的。如果你住在讲英语国家,你可能在使用 ASCII 码而没有意识到这一点。如果你住在欧洲,你可能使用一种扩展拉丁字符集,包含丹麦语和挪威语中的“ø”,匈牙利语中的“ő”,西班牙和布列塔尼语中的“ñ”,捷克语和斯洛伐克语中的“ň”。在本节中,我们将概述如何使用 Unicode 处理使用非 ASCII 字符集的文本。 +我们的程序经常需要处理不同的语言和不同的字符集。“纯文本”的概念是虚构的。如果你住在讲英语国家,你可能在使用 ASCII 码而没有意识到这一点。如果你住在欧洲,你可能使用一种扩展拉丁字符集,包含丹麦语和挪威语中的`ø`,匈牙利语中的`ő`,西班牙和布列塔尼语中的`ñ`,捷克语和斯洛伐克语中的`ň`。在本节中,我们将概述如何使用 Unicode 处理使用非 ASCII 字符集的文本。 ### 什么是 Unicode? -Unicode 支持超过一百万种字符。每个字符分配一个编号,称为编码点。在 Python 中,编码点写作`\u`*XXXX* 的形式,其中 *XXXX* 是四位十六进制形式数。 +Unicode 支持超过一百万种字符。每个字符分配一个编号,称为编码点。在 Python 中,编码点写作`\u*XXXX*`的形式,其中`*XXXX*`是四位十六进制形式数。 在一个程序中,我们可以像普通字符串那样操纵 Unicode 字符串。然而,当 Unicode 字符被存储在文件或在终端上显示,它们必须被编码为字节流。一些编码(如 ASCII 和 Latin-2)中每个编码点使用单字节,所以它们可以只支持 Unicode 的一个小的子集,足够单个语言使用了。其它的编码(如 UTF-8)使用多个字节,可以表示全部的 Unicode 字符。 @@ -584,7 +584,7 @@ Unicode 支持超过一百万种字符。每个字符分配一个编号,称为 >>> path = nltk.data.find('corpora/unicode_samples/polish-lat2.txt') ``` -Python 的`open()`函数可以读取编码的数据为 Unicode 字符串,并写出 Unicode 字符串的编码形式。它采用一个参数来指定正在读取或写入的文件的编码。因此,让我们使用编码`'latin2'`打开我们波兰语文件,并检查该文件的内容︰ +Python 的`open()`函数可以读取编码的数据为 Unicode 字符串,并写出 Unicode 字符串的编码形式。它采用一个参数来指定正在读取或写入的文件的编码。因此,让我们使用编码`'latin2'`打开我们波兰语文件,并检查该文件的内容: ```py >>> f = open(path, encoding='latin2') @@ -599,7 +599,7 @@ Jagiellońskiej w Krakowie, obejmują ponad 500 tys. zabytkowych archiwaliów, m.in. manuskrypty Goethego, Mozarta, Beethovena, Bacha. ``` -如果这不能在你的终端正确显示,或者我们想要看到字符的底层数值(或"代码点"),那么我们可以将所有的非 ASCII 字符转换成它们两位数`\x`*XX* 和四位数`\u`*XXXX* 表示法︰ +如果这不能在你的终端正确显示,或者我们想要看到字符的底层数值(或"代码点"),那么我们可以将所有的非 ASCII 字符转换成它们两位数`\x*XX*`和四位数`\u*XXXX*`表示法: ```py >>> f = open(path, encoding='latin2') @@ -614,9 +614,9 @@ b'Jagiello\\u0144skiej w Krakowie, obejmuj\\u0105 ponad 500 tys. zabytkowych' b'archiwali\\xf3w, m.in. manuskrypty Goethego, Mozarta, Beethovena, Bacha.' ``` -上面输出的第一行有一个以`\u`转义字符串开始的 Unicode 转义字符串,即`\u0144`。相关的 Unicode 字符在屏幕上将显示为字形ń。在前面例子中的第三行中,我们看到`\xf3`,对应字形为ó,在 128-255 的范围内。 +上面输出的第一行有一个以`\u`转义字符串开始的 Unicode 转义字符串,即`\u0144`。相关的 Unicode 字符在屏幕上将显示为字形`ń`。在前面例子中的第三行中,我们看到`\xf3`,对应字形为ó,在 128-255 的范围内。 -在 Python 3 中,源代码默认使用 UTF-8 编码,如果你使用的 IDLE 或另一个支持 Unicode 的程序编辑器,你可以在字符串中包含 Unicode 字符。可以使用`\u`*XXXX* 转义序列包含任意的 Unicode 字符。我们使用`ord()`找到一个字符的整数序数。例如︰ +在 Python 3 中,源代码默认使用 UTF-8 编码,如果你使用的 IDLE 或另一个支持 Unicode 的程序编辑器,你可以在字符串中包含 Unicode 字符。可以使用`\u*XXXX*`转义序列包含任意的 Unicode 字符。我们使用`ord()`找到一个字符的整数序数。例如: ```py >>> ord('ń') @@ -635,7 +635,7 @@ b'archiwali\\xf3w, m.in. manuskrypty Goethego, Mozarta, Beethovena, Bacha.' 决定屏幕上显示的字形的因素很多。如果你确定你的编码正确但你的 Python 代码仍然未能显示出你预期的字形,你应该检查你的系统上是否安装了所需的字体。可能需要配置你的区域设置来渲染 UTF-8 编码的字符,然后使用`print(nacute.encode('utf8'))`才能在你的终端看到ń显示。 -我们还可以看到这个字符在一个文本文件内是如何表示为字节序列的︰ +我们还可以看到这个字符在一个文本文件内是如何表示为字节序列的: ```py >>> nacute.encode('utf8') @@ -691,7 +691,7 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode ### 在 Python 中使用本地编码 -如果你习惯了使用特定的本地编码字符,你可能希望能够在一个 Python 文件中使用你的字符串输入及编辑的标准方法。为了做到这一点,你需要在你的文件的第一行或第二行中包含字符串:`'# -*- coding: <coding> -*-'`。请注意 *<coding>* 必须是像`'latin-1'`, `'big5'`或`'utf-8'`这样的字符串 (见 3.4)。 +如果你习惯了使用特定的本地编码字符,你可能希望能够在一个 Python 文件中使用你的字符串输入及编辑的标准方法。为了做到这一点,你需要在你的文件的第一行或第二行中包含字符串:`'# -*- coding: <coding> -*-'`。请注意``必须是像`'latin-1'`, `'big5'`或`'utf-8'`这样的字符串 (见 3.4)。 ![Images/polish-utf8.png](Images/5eeb4cf55b6d18d4bcb098fc72ddc6d7.jpg) @@ -701,13 +701,13 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode ## 3.4 使用正则表达式检测词组搭配 -许多语言处理任务都涉及模式匹配。例如:我们可以使用`endswith('ed')`找到以 ed 结尾的词。在 4.2 中我们看到过各种这样的“词测试”。正则表达式给我们一个更加强大和灵活的方法描述我们感兴趣的字符模式。 +许多语言处理任务都涉及模式匹配。例如:我们可以使用`endswith('ed')`找到以`ed`结尾的词。在 4.2 中我们看到过各种这样的“词测试”。正则表达式给我们一个更加强大和灵活的方法描述我们感兴趣的字符模式。 注意 -介绍正则表达式的其他出版物有很多,它们围绕正则表达式的语法组织,应用于搜索文本文件。我们不再赘述这些,只专注于在语言处理的不同阶段如何使用正则表达式。像往常一样,我们将采用基于问题的方式,只在解决实际问题需要时才介绍新特性。在我们的讨论中,我们将使用箭头来表示正则表达式,就像这样:«`patt`»。 +介绍正则表达式的其他出版物有很多,它们围绕正则表达式的语法组织,应用于搜索文本文件。我们不再赘述这些,只专注于在语言处理的不同阶段如何使用正则表达式。像往常一样,我们将采用基于问题的方式,只在解决实际问题需要时才介绍新特性。在我们的讨论中,我们将使用箭头来表示正则表达式,就像这样:`patt`。 -在 Python 中使用正则表达式,需要使用`import re`导入`re`库。我们还需要一个用于搜索的词汇列表;我们再次使用词汇语料库(4)。我们将对它进行预处理消除某些名称。 +在 Python 中使用正则表达式,需要使用`import re`导入`re`库。我们还需要一个用于搜索的词汇列表;我们再次使用词汇语料库`(4)`。我们将对它进行预处理消除某些名称。 ```py >>> import re @@ -716,14 +716,14 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode ### 使用基本的元字符 -让我们使用正则表达式«`ed 我们将使用函数`re.search(p, s)`检查字符串`s`中是否有模式`p`。我们需要指定感兴趣的字符,然后使用美元符号,它是正则表达式中有特殊用途的符号,用来匹配单词的末尾: +让我们使用正则表达式`'ed$'`,我们将使用函数`re.search(p, s)`检查字符串`s`中是否有模式`p`。我们需要指定感兴趣的字符,然后使用美元符号,它是正则表达式中有特殊用途的符号,用来匹配单词的末尾: ```py >>> [w for w in wordlist if re.search('ed$', w)] ['abaissed', 'abandoned', 'abased', 'abashed', 'abatised', 'abed', 'aborted', ...] ``` -`.`通配符匹配任何单个字符。假设我们有一个 8 个字母组成的词的字谜室,j 是其第三个字母,t 是其第六个字母。空白单元格中的每个地方,我们用一个句点: +`.`通配符匹配任何单个字符。假设我们有一个 8 个字母组成的词的字谜室,`j`是其第三个字母,`t`是其第六个字母。空白单元格中的每个地方,我们用一个句点: ```py >>> [w for w in wordlist if re.search('^..j..t..$', w)] @@ -732,9 +732,9 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode 注意 -**轮到你来**:驼字符`^`匹配字符串的开始,就像`如果我们不用这两个符号而使用«`..j..t..`»搜索,刚才例子中我们会得到什么样的结果? +**轮到你来**:驼字符`^`匹配字符串的开始,就像如果我们不用这两个符号而使用`..j..t..`搜索,刚才例子中我们会得到什么样的结果? -最后,`?`符合表示前面的字符是可选的。因此«`^e-?mail 我们可以使用`sum(1 for w in text if re.search('^e-?mail/font>, w))`计数一个文本中这个词(任一拼写形式)出现的总次数。 +最后,`?`符号表示前面的字符是可选的。因此我们可以使用`sum(1 for w in text if re.search('^e-?mail', w))`计数一个文本中这个词(任一拼写形式)出现的总次数。 ### 范围与闭包 @@ -742,18 +742,18 @@ NLTK 分词器允许 Unicode 字符串作为输入,并输出相应地 Unicode 图 3.5:T9:9 个键上的文本 -T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以相同击键顺序输入的词汇,叫做 textonyms。例如,hole 和 golf 都是通过序列 4653 输入。还有哪些其它词汇由相同的序列产生?这里我们使用正则表达式«`^[ghi][mno][jlk][def] +T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以相同击键顺序输入的词汇,叫做 textonyms。例如,`hole`和`golf`都是通过序列 4653 输入。还有哪些其它词汇由相同的序列产生?这里我们使用正则表达式`'^[ghi][mno][jlk][def]$'`。 ```py >>> [w for w in wordlist if re.search('^[ghi][mno][jlk][def]$', w)] ['gold', 'golf', 'hold', 'hole'] ``` -表达式的第一部分«`^[ghi]`»匹配以 g, h 或 i 开始的词。表达式的下一部分,«`[mno]`»限制了第二个字符是 m, n 或 o。第三部分和第四部分同样被限制。只有 4 个单词满足这些限制。注意,方括号内的字符的顺序是没有关系的,所以我们可以写成«`^[hig][nom][ljk][fed] +表达式的第一部分`^[ghi]`匹配以`g, h, i`开始的词。表达式的下一部分,`[mno]`限制了第二个字符是`m, n, o`。第三部分和第四部分同样被限制。只有 4 个单词满足这些限制。注意,方括号内的字符的顺序是没有关系的,所以我们可以写成`^[hig][nom][ljk][fed]$` 注意 -**轮到你来**:来看一些“手指绕口令”,只用一部分数字键盘搜索词汇。例如«`^[ghijklmno]+`-`和`+`表示什么意思? +**轮到你来**:来看一些“手指绕口令”,只用一部分数字键盘搜索词汇。例如`^[ghijklmno]+`的`+`表示什么意思? 让我们进一步探索`+`符号。请注意,它可以适用于单个字母或括号内的字母集: @@ -768,9 +768,9 @@ T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以 'hah', 'haha', 'hahaaa', 'hahah', 'hahaha', 'hahahaa', 'hahahah', 'hahahaha', ...] ``` -很显然,`+`简单地表示“前面的项目的一个或多个实例”,它可以是单独的字母如`m`,可以是一个集合如`[fed]`或者一个范围如`[d-f]`。现在让我们用`*`替换`+`,它表示“前面的项目的零个或多个实例”。正则表达式«`^m*i*n*e*me, min 和 mmmmm。请注意`+`和`*`符号有时被称为的 Kleene 闭包,或者干脆闭包。 +很显然,`+`简单地表示“前面的项目的一个或多个实例”,它可以是单独的字母如`m`,可以是一个集合如`[fed]`或者一个范围如`[d-f]`。现在让我们用`*`替换`+`,它表示“前面的项目的零个或多个实例”。正则表达式`^m*i*n*e*`匹配`me`, `min`和`mmmmm`。请注意`+`和`*`符号有时被称为的 Kleene 闭包,或者干脆闭包。 -运算符`^`当它出现在方括号内的第一个字符位置时有另外的功能。例如,«`[^aeiouAEIOU]`»匹配除元音字母之外的所有字母。我们可以搜索 NPS 聊天语料库中完全由非元音字母组成的词汇,使用«`^[^aeiouAEIOU]+请注意其中包含非字母字符。 +运算符`^`当它出现在方括号内的第一个字符位置时有另外的功能。例如,`[^aeiouAEIOU]`匹配除元音字母之外的所有字母。我们可以搜索 NPS 聊天语料库中完全由非元音字母组成的词汇,使用`^[^aeiouAEIOU]+`。请注意其中包含非字母字符。 下面是另外一些正则表达式的例子,用来寻找匹配特定模式的词符,这些例子演示如何使用一些新的符号:`\`, `{}`, `()`和`|`。 @@ -797,7 +797,7 @@ T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以 **轮到你来**:研究前面的例子,在你继续阅读之前尝试弄清楚`\`, `{}`, `()`和`|`这些符号的功能。 -你可能已经知道反斜杠表示其后面的字母不再有特殊的含义而是按照字面的表示匹配词中特定的字符。因此,虽然`.`很特别,但是`\.`只匹配一个句号。大括号表达式,如`{3,5}`, 表示前面的项目重复指定次数。管道字符表示从其左边的内容和右边的内容中选择一个。圆括号表示一个操作符的范围,它们可以与管道(或叫析取)符号一起使用,如«`w(i|e|ai|oo)t`»,匹配 wit, wet, wait 和 woot。你可以省略这个例子里的最后一个表达式中的括号,使用«`ed|ing +你可能已经知道反斜杠表示其后面的字母不再有特殊的含义而是按照字面的表示匹配词中特定的字符。因此,虽然`.`很特别,但是`\.`只匹配一个句号。大括号表达式,如`{3,5}`, 表示前面的项目重复指定次数。管道字符表示从其左边的内容和右边的内容中选择一个。圆括号表示一个操作符的范围,它们可以与管道(或叫析取)符号一起使用,如`w(i|e|ai|oo)t`,匹配`wit`, `wet`, `wait`和`woot`。你可以省略这个例子里的最后一个表达式中的括号,使用`ed|ing`。 我们已经看到的元字符总结在 3.3 中: @@ -826,7 +826,7 @@ T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以 注意 -**轮到你来**:在 W3C 日期时间格式中,日期像这样表示:2009-12-31。Replace the `?` in the following Python code with a regular expression, in order to convert the string `'2009-12-31'` to a list of integers `[2009, 12, 31]`: +**轮到你来**:在 W3C 日期时间格式中,日期像这样表示:2009-12-31。将以下 Python 代码中的`?`替换为正则表达式, 以便将字符串`'2009-12-31'`转换为整数列表`[2009, 12, 31]`: `[int(n) for n in re.findall(?, '2009-12-31')]` @@ -834,7 +834,7 @@ T9 系统用于在手机上输入文本(见 3.5))。两个或两个以上以 一旦我们会使用`re.findall()`从单词中提取素材,就可以在这些片段上做一些有趣的事情,例如将它们粘贴在一起或用它们绘图。 -英文文本是高度冗余的,忽略掉词内部的元音仍然可以很容易的阅读,有些时候这很明显。例如,declaration 变成 dclrtn,inalienable 变成 inlnble,保留所有词首或词尾的元音序列。在我们的下一个例子中,正则表达式匹配词首元音序列,词尾元音序列和所有的辅音;其它的被忽略。这三个析取从左到右处理,如果词匹配三个部分中的一个,正则表达式后面的部分将被忽略。我们使用`re.findall()`提取所有匹配的词中的字符,然后使`''.join()`将它们连接在一起(更多连接操作参见 3.9)。 +英文文本是高度冗余的,忽略掉词内部的元音仍然可以很容易的阅读,有些时候这很明显。例如,`declaration`变成`dclrtn`,`inalienable`变成`inlnble`,保留所有词首或词尾的元音序列。在我们的下一个例子中,正则表达式匹配词首元音序列,词尾元音序列和所有的辅音;其它的被忽略。这三个析取从左到右处理,如果词匹配三个部分中的一个,正则表达式后面的部分将被忽略。我们使用`re.findall()`提取所有匹配的词中的字符,然后使`''.join()`将它们连接在一起(更多连接操作参见 3.9)。 ```py >>> regexp = r'^[AEIOUaeiou]+|[AEIOUaeiou]+$|[^AEIOUaeiou]' @@ -851,7 +851,7 @@ rghts hve rsltd in brbrs acts whch hve outrgd the cnscnce of mnknd , and the advnt of a wrld in whch hmn bngs shll enjy frdm of spch and ``` -接下来,让我们将正则表达式与条件频率分布结合起来。在这里,我们将从罗托卡特语词汇中提取所有辅音-元音序列,如 ka 和 si。因为每部分都是成对的,它可以被用来初始化一个条件频率分布。然后我们为每对的频率画出表格: +接下来,让我们将正则表达式与条件频率分布结合起来。在这里,我们将从罗托卡特语词汇中提取所有辅音-元音序列,如`ka`和`si`。因为每部分都是成对的,它可以被用来初始化一个条件频率分布。然后我们为每对的频率画出表格: ```py >>> rotokas_words = nltk.corpus.toolbox.words('rotokas.dic') @@ -867,9 +867,9 @@ t 47 8 0 148 37 v 93 27 105 48 49 ``` -考查 s 行和 t 行,我们看到它们是部分的“互补分布”,这个证据表明它们不是这种语言中的独特音素。从而我们可以令人信服的从罗托卡特语字母表中去除 s,简单加入一个发音规则:当字母 t 跟在 i 后面时发 s 的音。(注意单独的条目 *su* 即 *kasuari*,‘cassowary’是从英语中借来的)。 +考查`s`行和`t`行,我们看到它们是部分的“互补分布”,这个证据表明它们不是这种语言中的独特音素。从而我们可以令人信服的从罗托卡特语字母表中去除`s`,简单加入一个发音规则:当字母`t`跟在`i`后面时发`s`的音。(注意单独的条目`su`即`kasuari`,`cassowary`是从英语中借来的)。 -如果我们想要检查表格中数字背后的词汇,有一个索引允许我们迅速找到包含一个给定的辅音-元音对的单词的列表将会有帮助,例如,`cv_index['su']`应该给我们所有含有 su 的词汇。下面是我们如何能做到这一点: +如果我们想要检查表格中数字背后的词汇,有一个索引允许我们迅速找到包含一个给定的辅音-元音对的单词的列表将会有帮助,例如,`cv_index['su']`应该给我们所有含有`su`的词汇。下面是我们如何能做到这一点: ```py >>> cv_word_pairs = [(cv, w) for w in rotokas_words @@ -882,11 +882,11 @@ v 93 27 105 48 49 'kapokao', 'kapokapo', 'kapokapo', 'kapokapoa', 'kapokapoa', 'kapokapora', ...] ``` -这段代码依次处理每个词`w`,对每一个词找出匹配正则表达式«`[ptksvr][aeiou]`»的所有子字符串。对于词 kasuari,它找到 ka, su 和 ri。因此,`cv_word_pairs`将包含`('ka', 'kasuari')`, `('su', 'kasuari')`和`('ri', 'kasuari')`。更进一步使用`nltk.Index()`转换成有用的索引。 +这段代码依次处理每个词`w`,对每一个词找出匹配正则表达式`[ptksvr][aeiou]`的所有子字符串。对于词`kasuari`,它找到`ka`, `su`和`ri`。因此,`cv_word_pairs`将包含`('ka', 'kasuari')`, `('su', 'kasuari')`和`('ri', 'kasuari')`。更进一步使用`nltk.Index()`转换成有用的索引。 ### 查找词干 -在使用网络搜索引擎时,我们通常不介意(甚至没有注意到)文档中的词汇与我们的搜索条件的后缀形式是否相同。查询 laptops 会找到含有 laptop 的文档,反之亦然。事实上,laptop 与 laptops 只是词典中的同一个词(或词条)的两种形式。对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。 +在使用网络搜索引擎时,我们通常不介意(甚至没有注意到)文档中的词汇与我们的搜索条件的后缀形式是否相同。查询`laptops`会找到含有`laptop`的文档,反之亦然。事实上,`laptop`与`laptops`只是词典中的同一个词(或词条)的两种形式。对于一些语言处理任务,我们想忽略词语结尾,只是处理词干。 抽出一个词的词干的方法有很多种。这里的是一种简单直观的方法,直接去掉任何看起来像一个后缀的字符: @@ -919,14 +919,14 @@ v 93 27 105 48 49 [('process', 'ing')] ``` -这看起来很有用途,但仍然有一个问题。让我们来看看另外的词,processes: +这看起来很有用途,但仍然有一个问题。让我们来看看另外的词,`processes`: ```py >>> re.findall(r'^(.*)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes') [('processe', 's')] ``` -正则表达式错误地找到了后缀-s,而不是后缀-es。这表明另一个微妙之处:星号操作符是“贪婪的”,所以表达式的`.*`部分试图尽可能多的匹配输入的字符串。如果我们使用“非贪婪”版本的“*”操作符,写成`*?`,我们就得到我们想要的: +正则表达式错误地找到了后缀`-s`,而不是后缀`-es`。这表明另一个微妙之处:星号操作符是“贪婪的”,所以表达式的`.*`部分试图尽可能多的匹配输入的字符串。如果我们使用“非贪婪”版本的“*”操作符,写成`*?`,我们就得到我们想要的: ```py >>> re.findall(r'^(.*?)(ing|ly|ed|ious|ies|ive|es|s|ment)$', 'processes') @@ -959,11 +959,11 @@ v 93 27 105 48 49 'not', 'from', 'some', 'farcical', 'aquatic', 'ceremony', '.'] ``` -请注意我们的正则表达式不但将 ponds 的 s 删除,也将 is 和 basis 的删除。它产生一些非词如 distribut 和 deriv,但这些在一些应用中是可接受的词干。 +请注意我们的正则表达式不但将`ponds`的`s`删除,也将`is`和`basis`的删除。它产生一些非词如`distribut`和`deriv`,但这些在一些应用中是可接受的词干。 ### 搜索已分词文本 -你可以使用一种特殊的正则表达式搜索一个文本中多个词(这里的文本是一个词符列表)。例如,`"<a> <man>"`找出文本中所有 a man 的实例。尖括号用于标记词符的边界,尖括号之间的所有空白都被忽略(这只对 NLTK 中的`findall()`方法处理文本有效)。在下面的例子中,我们使用`<.*>`❶,它将匹配所有单个词符,将它括在括号里,于是只匹配词(例如 monied)而不匹配短语(例如,a monied man)会生成。第二个例子找出以词 bro 结尾的三个词组成的短语❷。最后一个例子找出以字母 l 开始的三个或更多词组成的序列❸。 +你可以使用一种特殊的正则表达式搜索一个文本中多个词(这里的文本是一个词符列表)。例如,`"<a> <man>"`找出文本中所有`a man`的实例。尖括号用于标记词符的边界,尖括号之间的所有空白都被忽略(这只对 NLTK 中的`findall()`方法处理文本有效)。在下面的例子中,我们使用`<.*>`❶,它将匹配所有单个词符,将它括在括号里,于是只匹配词(例如`monied`)而不匹配短语(例如,`a monied man`)会生成。第二个例子找出以词`bro`结尾的三个词组成的短语❷。最后一个例子找出以字母`l`开始的三个或更多词组成的序列❸。 ```py >>> from nltk.corpus import gutenberg, nps_chat @@ -983,9 +983,9 @@ la la; lovely lol lol love; lol lol lol.; la la la; la la la 注意 -**轮到你来**:巩固你对正则表达式模式与替换的理解,使用`nltk.re_show(`_p, s_`)`,它能标注字符串 *s* 中所有匹配模式 *p* 的地方,以及`nltk.app.nemo()`,它能提供一个探索正则表达式的图形界面。更多的练习,可以尝试本章尾的正则表达式的一些练习。 +**轮到你来**:巩固你对正则表达式模式与替换的理解,使用`nltk.re_show(p, s)`,它能标注字符串`s`中所有匹配模式`p`的地方,以及`nltk.app.nemo()`,它能提供一个探索正则表达式的图形界面。更多的练习,可以尝试本章尾的正则表达式的一些练习。 -当我们研究的语言现象与特定词语相关时建立搜索模式是很容易的。在某些情况下,一个小小的创意可能会花很大功夫。例如,在大型文本语料库中搜索 x and other ys 形式的表达式能让我们发现上位词(见 5): +当我们研究的语言现象与特定词语相关时建立搜索模式是很容易的。在某些情况下,一个小小的创意可能会花很大功夫。例如,在大型文本语料库中搜索`x and other ys`形式的表达式能让我们发现上位词(见 5): ```py >>> from nltk.corpus import brown @@ -998,7 +998,7 @@ objects; military and other areas; demands and other factors; abstracts and other compilations; iron and other metals ``` -只要有足够多的文本,这种做法会给我们一整套有用的分类标准信息,而不需要任何手工劳动。然而,我们的搜索结果中通常会包含误报,即我们想要排除的情况。例如,结果 demands and other factors 暗示 demand 是类型 factor 的一个实例,但是这句话实际上是关于要求增加工资的。尽管如此,我们仍可以通过手工纠正这些搜索的结果来构建自己的英语概念的本体。 +只要有足够多的文本,这种做法会给我们一整套有用的分类标准信息,而不需要任何手工劳动。然而,我们的搜索结果中通常会包含误报,即我们想要排除的情况。例如,结果`demands and other factors`暗示`demand`是类型`factor`的一个实例,但是这句话实际上是关于要求增加工资的。尽管如此,我们仍可以通过手工纠正这些搜索的结果来构建自己的英语概念的本体。 注意 @@ -1008,11 +1008,11 @@ abstracts and other compilations; iron and other metals 注意 -**轮到你来**:查找模式 as x as y 的实例以发现实体及其属性信息。 +**轮到你来**:查找模式`as x as y`的实例以发现实体及其属性信息。 ## 3.6 规范化文本 -在前面的程序例子中,我们在处理文本词汇前经常要将文本转换为小写,即`set(w.lower() for w in text)`。通过使用`lower()`我们将文本规范化为小写,这样一来 The 与 the 的区别被忽略。我们常常想比这走得更远,去掉所有的词缀以及提取词干的任务等。更进一步的步骤是确保结果形式是字典中确定的词,即叫做词形归并的任务。我们依次讨论这些。首先,我们需要定义我们将在本节中使用的数据: +在前面的程序例子中,我们在处理文本词汇前经常要将文本转换为小写,即`set(w.lower() for w in text)`。通过使用`lower()`我们将文本规范化为小写,这样一来`The`与`the`的区别被忽略。我们常常想比这走得更远,去掉所有的词缀以及提取词干的任务等。更进一步的步骤是确保结果形式是字典中确定的词,即叫做词形归并的任务。我们依次讨论这些。首先,我们需要定义我们将在本节中使用的数据: ```py >>> raw = """DENNIS: Listen, strange women lying in ponds distributing swords @@ -1023,7 +1023,7 @@ abstracts and other compilations; iron and other metals ### 词干提取器 -NLTK 中包括几个现成的词干提取器,如果你需要一个词干提取器,你应该优先使用它们中的一个,而不是使用正则表达式制作自己的词干提取器,因为 NLTK 中的词干提取器能处理的不规则的情况很广泛。Porter 和 Lancaster 词干提取器按照它们自己的规则剥离词缀。请看 Porter 词干提取器正确处理了词 lying(将它映射为 lie),而 Lancaster 词干提取器并没有处理好。 +NLTK 中包括几个现成的词干提取器,如果你需要一个词干提取器,你应该优先使用它们中的一个,而不是使用正则表达式制作自己的词干提取器,因为 NLTK 中的词干提取器能处理的不规则的情况很广泛。`Porter`和`Lancaster`词干提取器按照它们自己的规则剥离词缀。请看`Porter`词干提取器正确处理了词`lying`(将它映射为`lie`),而`Lancaster`词干提取器并没有处理好。 ```py >>> porter = nltk.PorterStemmer() @@ -1040,7 +1040,7 @@ NLTK 中包括几个现成的词干提取器,如果你需要一个词干提取 'from', 'som', 'farc', 'aqu', 'ceremony', '.'] ``` -词干提取过程没有明确定义,我们通常选择心目中最适合我们的应用的词干提取器。如果你要索引一些文本和使搜索支持不同词汇形式的话,Porter 词干提取器是一个很好的选择(3.6 所示,它采用*面向对象*编程技术,这超出了本书的范围,字符串格式化技术将在 3.9 讲述,`enumerate()`函数将在 4.2 解释)。 +词干提取过程没有明确定义,我们通常选择心目中最适合我们的应用的词干提取器。如果你要索引一些文本和使搜索支持不同词汇形式的话,`Porter`词干提取器是一个很好的选择(3.6 所示,它采用*面向对象*编程技术,这超出了本书的范围,字符串格式化技术将在 3.9 讲述,`enumerate()`函数将在 4.2 解释)。 ```py class IndexedText(object): @@ -1067,7 +1067,7 @@ class IndexedText(object): ### 词形归并 -WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。这个额外的检查过程使词形归并器比刚才提到的词干提取器要慢。请注意,它并没有处理 lying,但它将 women 转换为 woman。 +WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。这个额外的检查过程使词形归并器比刚才提到的词干提取器要慢。请注意,它并没有处理`lying`,但它将`women`转换为`woman`。 ```py >>> wnl = nltk.WordNetLemmatizer() @@ -1114,7 +1114,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 "it's", 'always', 'pepper', 'that', 'makes', 'people', "hot-tempered,'..."] ``` -正则表达式«`[ \t\n]+`»匹配一个或多个空格、制表符(`\t`)或换行符(`\n`)。其他空白字符,如回车和换页符,实际上应该也包含。于是,我们将使用一个`re`库内置的缩写`\s`,它表示匹配所有空白字符。前面的例子中第二条语句可以改写为`re.split(r'\s+', raw)`。 +正则表达式`[ \t\n]+`匹配一个或多个空格、制表符(`\t`)或换行符(`\n`)。其他空白字符,如回车和换页符,实际上应该也包含。于是,我们将使用一个`re`库内置的缩写`\s`,它表示匹配所有空白字符。前面的例子中第二条语句可以改写为`re.split(r'\s+', raw)`。 注意 @@ -1131,7 +1131,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 ''] ``` -可以看到,在开始和结尾都给了我们一个空字符串(要了解原因请尝试`'xx'.split('x')`)。通过`re.findall(r'\w+', raw)`使用模式匹配词汇而不是空白符号,我们得到相同的标识符,但没有空字符串。现在,我们正在匹配词汇,我们处在扩展正则表达式覆盖更广泛的情况的位置。正则表达式«`\w+|\S\w*`»将首先尝试匹配词中字符的所有序列。如果没有找到匹配的,它会尝试匹配后面跟着词中字符的任何*非*空白字符(`\S`是`\s`的补)。这意味着标点会与跟在后面的字母(如's)在一起,但两个或两个以上的标点字符序列会被分割。 +可以看到,在开始和结尾都给了我们一个空字符串(要了解原因请尝试`'xx'.split('x')`)。通过`re.findall(r'\w+', raw)`使用模式匹配词汇而不是空白符号,我们得到相同的标识符,但没有空字符串。现在,我们正在匹配词汇,我们处在扩展正则表达式覆盖更广泛的情况的位置。正则表达式`\w+|\S\w*`将首先尝试匹配词中字符的所有序列。如果没有找到匹配的,它会尝试匹配后面跟着词中字符的任何*非*空白字符(`\S`是`\s`的补)。这意味着标点会与跟在后面的字母(如`'s`)在一起,但两个或两个以上的标点字符序列会被分割。 ```py >>> re.findall(r'\w+|\S\w*', raw) @@ -1142,7 +1142,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 'makes', 'people', 'hot', '-tempered', ',', "'", '.', '.', '.'] ``` -让我们扩展前面表达式中的`\w+`,允许连字符和撇号:«`\w+([-']\w+)*`»。这个表达式表示`\w+`后面跟零个或更多`[-']\w+`的实例;它会匹配 hot-tempered 和 it's。(我们需要在这个表达式中包含`?:`,原因前面已经讨论过。)我们还将添加一个模式来匹配引号字符,让它们与它们包括的文字分开。 +让我们扩展前面表达式中的`\w+`,允许连字符和撇号:`\w+([-']\w+)*`。这个表达式表示`\w+`后面跟零个或更多`[-']\w+`的实例;它会匹配`hot-tempered`和`it's`。(我们需要在这个表达式中包含`?:`,原因前面已经讨论过。)我们还将添加一个模式来匹配引号字符,让它们与它们包括的文字分开。 ```py >>> print(re.findall(r"\w+(?:[-']\w+)*|'|[-.(]+|\S\w*", raw)) @@ -1153,7 +1153,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 'that', 'makes', 'people', 'hot-tempered', ',', "'", '...'] ``` -上面的表达式也包括«`[-.(]+`»,这会使双连字符、省略号和左括号被单独分词。 +上面的表达式也包括`[-.(]+`,这会使双连字符、省略号和左括号被单独分词。 3.4 列出了我们已经在本节中看到的正则表达式字符类符号,以及一些其他有用的符号。 @@ -1186,7 +1186,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 在开发分词器时,访问已经手工分词的原始文本是有益的,这可以让你的分词器的输出结果与高品质(或称“黄金标准”)的词符进行比较。NLTK 语料库集合包括宾州树库的数据样本,包括《华尔街日报》原始文本(`nltk.corpus.treebank_raw.raw()`)和分好词的版本(`nltk.corpus.treebank.words()`)。 -分词的最后一个问题是缩写的存在,如 didn't。如果我们想分析一个句子的意思,将这种形式规范化为两个独立的形式:did 和 n't(或 not)可能更加有用。我们可以通过查表来做这项工作。 +分词的最后一个问题是缩写的存在,如`didn't`。如果我们想分析一个句子的意思,将这种形式规范化为两个独立的形式:`did`和`n't`(或`not`)可能更加有用。我们可以通过查表来做这项工作。 ## 3.8 分割 @@ -1203,7 +1203,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 20.250994070456922 ``` -在其他情况下,文本可能只是作为一个字符流。在将文本分词之前,我们需要将它分割成句子。NLTK 通过包含 Punkt 句子分割器[(Kiss & Strunk, 2006)](./bibliography.html#kissstrunk2006)使得这个功能便于使用。这里是使用它为一篇小说文本断句的例子。(请注意,如果在你读到这篇文章时分割器内部数据已经更新过,你会看到不同的输出): +在其他情况下,文本可能只是作为一个字符流。在将文本分词之前,我们需要将它分割成句子。NLTK 通过包含`Punkt`句子分割器[(Kiss & Strunk, 2006)](./bibliography.html#kissstrunk2006)使得这个功能便于使用。这里是使用它为一篇小说文本断句的例子。(请注意,如果在你读到这篇文章时分割器内部数据已经更新过,你会看到不同的输出): ```py >>> text = nltk.corpus.gutenberg.raw('chesterton-thursday.txt') @@ -1230,13 +1230,13 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 请注意,这个例子其实是一个单独的句子,报道 Lucian Gregory 先生的演讲。然而,引用的演讲包含几个句子,这些已经被分割成几个单独的字符串。这对于大多数应用程序是合理的行为。 -断句是困难的,因为句号会被用来标记缩写而另一些句号同时标记缩写和句子结束,就像发生在缩写如 U.S.A.上的那样。 +断句是困难的,因为句号会被用来标记缩写而另一些句号同时标记缩写和句子结束,就像发生在缩写如`U.S.A.`上的那样。 断句的另一种方法见 2 节。 ### 分词 -对于一些书写系统,由于没有词的可视边界表示这一事实,文本分词变得更加困难。例如,在中文中,三个字符的字符串:爱国人(ai4 “love” [verb], guo3 “country”,ren2 “person”) 可以被分词为“爱国/人”,“country-loving person”,或者“爱/国人”,“love country-person”。 +对于一些书写系统,由于没有词的可视边界表示这一事实,文本分词变得更加困难。例如,在中文中,三个字符的字符串:爱国人`(ai4 "love" [verb], guo3 "country", ren2 "person")` 可以被分词为“爱国/人”,`country-loving person`,或者“爱/国人”,`love country-person`。 类似的问题在口语语言处理中也会出现,听者必须将连续的语音流分割成单个的词汇。当我们事先不认识这些词时,这个问题就演变成一个特别具有挑战性的版本。语言学习者会面对这个问题,例如小孩听父母说话。考虑下面的人为构造的例子,单词的边界已被去除: @@ -1246,7 +1246,7 @@ WordNet 词形归并器只在产生的词在它的词典中时才删除词缀。 >>> seg2 = "0100100100100001001001000010100100010010000100010010000" ``` -观察由 0 和 1 组成的分词表示字符串。它们比源文本短一个字符,因为长度为 n 文本可以在 n-1 个地方被分割。3.7 中的`segment()`函数演示了我们可以从这个表示回到初始分词的文本。 +观察由 0 和 1 组成的分词表示字符串。它们比源文本短一个字符,因为长度为`n`文本可以在`n-1`个地方被分割。3.7 中的`segment()`函数演示了我们可以从这个表示回到初始分词的文本。 ```py def segment(text, segs): @@ -1260,7 +1260,7 @@ def segment(text, segs): return words ``` -现在分词的任务变成了一个搜索问题:找到将文本字符串正确分割成词汇的字位串。我们假定学习者接收词,并将它们存储在一个内部词典中。给定一个合适的词典,是能够由词典中的词的序列来重构源文本的。根据[(Brent, 1995)](./bibliography.html#brent1995),我们可以定义一个目标函数,一个打分函数,我们将基于词典的大小和从词典中重构源文本所需的信息量尽力优化它的值。我们在 3.8 中说明了这些。 +现在分词的任务变成了一个搜索问题:找到将文本字符串正确分割成词汇的字位串。我们假定学习者接收词,并将它们存储在一个内部词典中。给定一个合适的词典,是能够由词典中的词的序列来重构源文本的。根据[(Brent, 1995)](./bibliography.html#brent1995),我们可以定义一个目标函数,一个打分函数,我们将基于词典的大小和从词典中重构源文本所需的信息量尽力优化它的值。我们在 3.8 中说明了这些。 ![Images/brent.png](Images/ced4e829d6a662a2be20187f9d7b71b5.jpg) @@ -1276,7 +1276,7 @@ def evaluate(text, segs): return text_size + lexicon_size ``` -最后一步是寻找最小化目标函数值的 0 和 1 的模式,如 3.10 所示。请注意,最好的分词包括像 thekitty 这样的“词”,因为数据中没有足够的证据进一步分割这个词。 +最后一步是寻找最小化目标函数值的 0 和 1 的模式,如 3.10 所示。请注意,最好的分词包括像`thekitty`这样的“词”,因为数据中没有足够的证据进一步分割这个词。 ```py from random import randint @@ -1573,7 +1573,7 @@ After (5), all (3), is (2), said (4), and (3), done (4), , (1), more * 我们可以通过打开一个用于写入的文件`output_file = open('output.txt', 'w')`来向文件写入文本,然后添加内容到文件中`print("Monty Python", file=output_file)`。 * 在网上找到的文本可能包含不需要的内容(如页眉、页脚和标记),在我们做任何语言处理之前需要去除它们。 * 分词是将文本分割成基本单位或词符,例如词和标点符号等。基于空格符的分词对于许多应用程序都是不够的,因为它会捆绑标点符号和词。NLTK 提供了一个现成的分词器`nltk.word_tokenize()`。 -* 词形归并是一个过程,将一个词的各种形式(如 appeared,appears)映射到这个词标准的或引用的形式,也称为词位或词元(如 appear)。 +* 词形归并是一个过程,将一个词的各种形式(如`appeared`,`appears`)映射到这个词标准的或引用的形式,也称为词位或词元(如`appear`)。 * 正则表达式是用来指定模式的一种强大而灵活的方法。一旦我们导入`re`模块,我们就可以使用`re.findall()`来找到一个字符串中匹配一个模式的所有子字符串。 * 如果一个正则表达式字符串包含一个反斜杠,你应该使用带有一个`r`前缀的原始字符串:`r'regexp'`,来告诉 Python 不要预处理这个字符串。 * 当某些字符前使用了反斜杠时,例如`\n`, 处理时会有特殊的含义(换行符);然而,当反斜杠用于正则表达式通配符和操作符之前时,如`\.`, `\|`, `\ @@ -1585,7 +1585,7 @@ After (5), all (3), is (2), said (4), and (3), done (4), , (1), more 更多的使用 NLTK 处理词汇的例子请参阅`http://nltk.org/howto`上的分词、词干提取以及语料库 HOWTO 文档。[(Jurafsky & Martin, 2008)](./bibliography.html#jurafskymartin2008)的第 2、3 章包含正则表达式和形态学的更高级的材料。Python 文本处理更广泛的讨论请参阅[(Mertz, 2003)](./bibliography.html#mertz2003tpp)。规范非标准词的信息请参阅[(Sproat et al, 2001)](./bibliography.html#sproat2001nor) -关于正则表达式的参考材料很多,无论是理论的还是实践的。在 Python 中使用正则表达式的一个入门教程,请参阅 Kuchling 的 *Regular Expression HOWTO*,`http://www.amk.ca/python/howto/regex/`。关于使用正则表达式的全面而详细的手册,请参阅[(Friedl, 2002)](./bibliography.html#friedl2002mre),其中涵盖包括 Python 在内大多数主要编程语言的语法。其他材料还包括[(Jurafsky & Martin, 2008)](./bibliography.html#jurafskymartin2008)的第 2.1 节,[(Mertz, 2003)](./bibliography.html#mertz2003tpp)的第 3 章。 +关于正则表达式的参考材料很多,无论是理论的还是实践的。在 Python 中使用正则表达式的一个入门教程,请参阅 Kuchling 的《Regular Expression HOWTO》,`http://www.amk.ca/python/howto/regex/`。关于使用正则表达式的全面而详细的手册,请参阅[(Friedl, 2002)](./bibliography.html#friedl2002mre),其中涵盖包括 Python 在内大多数主要编程语言的语法。其他材料还包括[(Jurafsky & Martin, 2008)](./bibliography.html#jurafskymartin2008)的第 2.1 节,[(Mertz, 2003)](./bibliography.html#mertz2003tpp)的第 3 章。 网上有许多关于 Unicode 的资源。以下是与处理 Unicode 的 Python 的工具有关的有益的讨论: @@ -1596,7 +1596,7 @@ After (5), all (3), is (2), said (4), and (3), done (4), , (1), more SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点关注中文文本分词的问题。我们分割英文文本的方法依据[(Brent, 1995)](./bibliography.html#brent1995);这项工作属于语言获取领域[(Niyogi, 2006)](./bibliography.html#niyogi2006)。 -搭配是多词表达式的一种特殊情况。一个多词表达式是一个小短语,仅从它的词汇不能预测它的意义和其他属性,例如 part of speech [(Baldwin & Kim, 2010)](./bibliography.html#baldwinkim2010)。 +搭配是多词表达式的一种特殊情况。一个多词表达式是一个小短语,仅从它的词汇不能预测它的意义和其他属性,例如词性[(Baldwin & Kim, 2010)](./bibliography.html#baldwinkim2010)。 模拟退火是一种启发式算法,找寻在一个大型的离散的搜索空间上的一个函数的最佳值的最好近似,基于对金属冶炼中的退火的模拟。该技术在许多人工智能文本中都有描述。 @@ -1604,7 +1604,7 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 ## 3.12 练习 -1. ☼ 定义一个字符串`s = 'colorless'`。写一个 Python 语句将其变为“colourless”,只使用切片和连接操作。 +1. ☼ 定义一个字符串`s = 'colorless'`。写一个 Python 语句将其变为`colourless`,只使用切片和连接操作。 2. ☼ 我们可以使用切片符号删除词汇形态上的结尾。例如,`'dogs'[:-1]`删除了`dogs`的最后一个字符,留下`dog`。使用切片符号删除下面这些词的词缀(我们插入了一个连字符指示词缀的边界,请在你的字符串中省略掉连字符): `dish-es`, `run-ning`, `nation-ality`, `un-do`, `pre-heat`。 @@ -1627,8 +1627,8 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 7. ☼ 写正则表达式匹配下面字符串类: - > 1. 一个单独的限定符(假设只有 a, an 和 the 为限定符)。 - > 2. 整数加法和乘法的算术表达式,如`2*3+8`。 + 1. 一个单独的限定符(假设只有`a, an, the`为限定符)。 + 2. 整数加法和乘法的算术表达式,如`2*3+8`。 8. ☼ 写一个工具函数以 URL 为参数,返回删除所有的 HTML 标记的 URL 的内容。使用`from urllib import request`和`request.urlopen('http://nltk.org/').read().decode('utf8')`来访问 URL 的内容。 9. ☼ 将一些文字保存到文件`corpus.txt`。定义一个函数`load(f)`以要读取的文件名为其唯一参数,返回包含文件中文本的字符串。 @@ -1668,7 +1668,7 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 17. ☼ 格式化字符串`%6s`与`%-6s`用来显示长度大于 6 个字符的字符串时,会发生什么? -18. ◑ 阅读语料库中的一些文字,为它们分词,输出其中出现的所有 wh-类型词的列表。(英语中的 wh-类型词被用在疑问句,关系从句和感叹句:who, which, what 等。)按顺序输出它们。在这个列表中有因为有大小写或标点符号的存在而重复的词吗? +18. ◑ 阅读语料库中的一些文字,为它们分词,输出其中出现的所有`wh-`类型词的列表。(英语中的`wh-`类型词被用在疑问句,关系从句和感叹句:`who, which, what`等。)按顺序输出它们。在这个列表中有因为有大小写或标点符号的存在而重复的词吗? 19. ◑ 创建一个文件,包含词汇和(任意指定)频率,其中每行包含一个词,一个空格和一个正整数,如`fuzzy 53`。使用`open(filename).readlines()`将文件读入一个 Python 列表。接下来,使用`split()`将每一行分成两个字段,并使用`int()`将其中的数字转换为一个整数。结果应该是一个列表形式:`[['fuzzy', 53], ...]`。 @@ -1678,11 +1678,11 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 22. ◑ 使用上面建议的正则表达式处理网址`http://news.bbc.co.uk/`,检查处理结果。你会看到那里仍然有相当数量的非文本数据,特别是 JavaScript 命令。你可能还会发现句子分割没有被妥善保留。定义更深入的正则表达式,改善此网页文本的提取。 -23. ◑ 你能写一个正则表达式以这样的方式来分词吗,将词 don't 分为 do 和 n't?解释为什么这个正则表达式无法正常工作:«`n't|\w+`»。 +23. ◑ 你能写一个正则表达式以这样的方式来分词吗,将词`don't`分为`do`和`n't`?解释为什么这个正则表达式无法正常工作:`n't|\w+`。 24. ◑ 尝试编写代码将文本转换成 *hAck3r*,使用正则表达式和替换,其中`e` → `3`, `i` → `1`, `o` → `0`, `l` → `|`, `s` → `5`, `.`→ `5w33t!`, `ate` → `8`。在转换之前将文本规范化为小写。自己添加更多的替换。现在尝试将`s`映射到两个不同的值:词开头的`s`映射为` -25. ◑ *Pig Latin* 是英语文本的一个简单的变换。文本中每个词的按如下方式变换:将出现在词首的所有辅音(或辅音群)移到词尾,然后添加 ay,例如 string → ingstray, idle → idleay。`http://en.wikipedia.org/wiki/Pig_Latin` +25. ◑ *Pig Latin* 是英语文本的一个简单的变换。文本中每个词的按如下方式变换:将出现在词首的所有辅音(或辅音群)移到词尾,然后添加`ay`,例如`string → ingstray`, `idle → idleay`。`http://en.wikipedia.org/wiki/Pig_Latin` 1. 写一个函数转换一个词为 Pig Latin。 2. 写代码转换文本而不是单个的词。 @@ -1691,18 +1691,18 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 27. ◑ Python 的`random`模块包括函数`choice()`,它从一个序列中随机选择一个项目,例如`choice("aehh ")`会产生四种可能的字符中的一个,字母`h`的几率是其它字母的两倍。写一个表达式产生器,从字符串`"aehh "`产生 500 个随机选择的字母的序列,并将这个表达式写入函数`''.join()`调用中,将它们连接成一个长字符串。你得到的结果应该看起来像失去控制的喷嚏或狂笑:`he haha ee heheeh eha`。使用`split()`和`join()`再次规范化这个字符串中的空格。 -28. ◑ 考虑下面的摘自 MedLine 语料库的句子中的数字表达式:The corresponding free cortisol fractions in these sera were 4.53 +/- 0.15% and 8.16 +/- 0.23%, respectively.我们应该说数字表达式 4.53 +/- 0.15%是三个词吗?或者我们应该说它是一个单独的复合词?或者我们应该说它实际上是*九*个词,因为它读作“four point five three,plus or minus fifteen percent”?或者我们应该说这不是一个“真正的”词,因为它不会出现在任何词典中?讨论这些不同的可能性。你能想出产生这些答案中至少两个以上可能性的应用领域吗? +28. ◑ 考虑下面的摘自 MedLine 语料库的句子中的数字表达式:`The corresponding free cortisol fractions in these sera were 4.53 +/- 0.15% and 8.16 +/- 0.23%, respectively.`。我们应该说数字表达式`4.53 +/- 0.15%`是三个词吗?或者我们应该说它是一个单独的复合词?或者我们应该说它实际上是*九*个词,因为它读作`four point five three,plus or minus fifteen percent`?或者我们应该说这不是一个“真正的”词,因为它不会出现在任何词典中?讨论这些不同的可能性。你能想出产生这些答案中至少两个以上可能性的应用领域吗? -29. ◑ 可读性测量用于为一个文本的阅读难度打分,给语言学习者挑选适当难度的文本。在一个给定的文本中,让我们定义μ<sub>w</sub>为每个词的平均字母数,μ<sub>s</sub>为每个句子的平均词数。文本自动可读性指数(ARI)被定义为: `4.71` μ<sub>w</sub> `+ 0.5` μ<sub>s</sub> `- 21.43`。计算布朗语料库各部分的 ARI 得分,包括`f`(lore)和`j`(learned)部分。利用`nltk.corpus.brown.words()`产生一个词汇序列,`nltk.corpus.brown.sents()`产生一个句子的序列的事实。 +29. ◑ 可读性测量用于为一个文本的阅读难度打分,给语言学习者挑选适当难度的文本。在一个给定的文本中,让我们定义`μ[w]`为每个词的平均字母数,`μ[s]`为每个句子的平均词数。文本自动可读性指数(ARI)被定义为:`4.71 * μ[w] + 0.5 μ[s] - 21.43`。计算布朗语料库各部分的 ARI 得分,包括`f`(lore)和`j`(learned)部分。利用`nltk.corpus.brown.words()`产生一个词汇序列,`nltk.corpus.brown.sents()`产生一个句子的序列的事实。 -30. ◑ 使用 Porter 词干提取器规范化一些已标注的文本,对每个词调用提取词干器。用 Lancaster 词干提取器做同样的事情,看看你是否能观察到一些差别。 +30. ◑ 使用`Porter`词干提取器规范化一些已标注的文本,对每个词调用提取词干器。用`Lancaster`词干提取器做同样的事情,看看你是否能观察到一些差别。 31. ◑ 定义变量`saying`包含列表`['After', 'all', 'is', 'said', 'and', 'done', ',', 'more', 'is', 'said', 'than', 'done', '.']`。使用`for`循环处理这个列表,并将结果存储在一个新的链表`lengths`中。提示:使用`lengths = []`,从分配一个空列表给`lengths`开始。然后每次循环中用`append()`添加另一个长度值到列表中。现在使用列表推导做同样的事情。 -32. ◑ 定义一个变量`silly`包含字符串:`'newly formed bland ideas are inexpressible in an infuriating way'`。(这碰巧是合法的解释,讲英语西班牙语双语者可以适用于乔姆斯基著名的无意义短语,colorless green ideas sleep furiously,来自维基百科)。编写代码执行以下任务: +32. ◑ 定义一个变量`silly`包含字符串:`'newly formed bland ideas are inexpressible in an infuriating way'`。(这碰巧是合法的解释,讲英语西班牙语双语者可以适用于乔姆斯基著名的无意义短语,`colorless green ideas sleep furiously`,来自维基百科)。编写代码执行以下任务: 1. 分割`silly`为一个字符串列表,每一个词一个字符串,使用 Python 的`split()`操作,并保存到叫做`bland`的变量中。 - 2. 提取`silly`中每个词的第二个字母,将它们连接成一个字符串,得到`'eoldrnnnna'`'。 + 2. 提取`silly`中每个词的第二个字母,将它们连接成一个字符串,得到`'eoldrnnnna'`。 3. 使用`join()`将`bland`中的词组合回一个单独的字符串。确保结果字符串中的词以空格隔开。 4. 按字母顺序输出`silly`中的词,每行一个。 33. ◑ `index()`函数可用于查找序列中的项目。例如,`'inexpressible'.index('e')`告诉我们字母`e`的第一个位置的索引值。 @@ -1710,40 +1710,40 @@ SIGHAN,ACL 中文语言处理特别兴趣小组`http://sighan.org/`,重点 1. 当你查找一个子字符串会发生什么,如`'inexpressible'.index('re')`? 2. 定义一个变量`words`,包含一个词列表。现在使用`words.index()`来查找一个单独的词的位置。 3. 定义上一个练习中的变量`silly`。使用`index()`函数结合列表切片,建立一个包括`silly`中`in`之前(但不包括)的所有的词的列表`phrase`。 -34. ◑ 编写代码,将国家的形容词转换为它们对应的名词形式,如将 Canadian 和 Australian 转换为 Canada 和 Australia(见`http://en.wikipedia.org/wiki/List_of_adjectival_forms_of_place_names`)。 +34. ◑ 编写代码,将国家的形容词转换为它们对应的名词形式,如将`Canadian`和`Australian`转换为`Canada`和`Australia`(见`http://en.wikipedia.org/wiki/List_of_adjectival_forms_of_place_names`)。 -35. ◑ 阅读 LanguageLog 中关于短语的 as best as p can 和 as best p can 形式的帖子,其中 p 是一个代名词。在一个语料库和 3.5 中描述的搜索已标注的文本的`findall()`方法的帮助下,调查这一现象。`http://itre.cis.upenn.edu/~myl/languagelog/archives/002733.html` +35. ◑ 阅读 LanguageLog 中关于短语的`as best as p can`和`as best p can`形式的帖子,其中`p`是一个代名词。在一个语料库和 3.5 中描述的搜索已标注的文本的`findall()`方法的帮助下,调查这一现象。`http://itre.cis.upenn.edu/~myl/languagelog/archives/002733.html` 36. ◑ 研究《创世记》的 lolcat 版本,使用`nltk.corpus.genesis.words('lolcat.txt')`可以访问,和`http://www.lolcatbible.com/index.php?title=How_to_speak_lolcat`上将文本转换为 lolspeak 的规则。定义正则表达式将英文词转换成相应的 lolspeak 词。 37. ◑ 使用`help(re.sub)`和参照本章的深入阅读,阅读有关`re.sub()`函数来使用正则表达式进行字符串替换。使用`re.sub`编写代码从一个 HTML 文件中删除 HTML 标记,规范化空格。 -38. ★ 分词的一个有趣的挑战是已经被分割的跨行的词。例如如果 *long-term* 被分割,我们就得到字符串`long-\nterm`。 +38. ★ 分词的一个有趣的挑战是已经被分割的跨行的词。例如如果`long-term`被分割,我们就得到字符串`long-\nterm`。 1. 写一个正则表达式,识别连字符连结的跨行处的词汇。这个表达式将需要包含`\n`字符。 2. 使用`re.sub()`从这些词中删除`\n`字符。 3. 你如何确定一旦换行符被删除后不应该保留连字符的词汇,如`'encyclo-\npedia'`? 39. ★ 阅读维基百科 *Soundex* 条目。用 Python 实现这个算法。 -40. ★ 获取两个或多个文体的原始文本,计算它们各自的在前面关于阅读难度的练习中描述的阅读难度得分。例如,比较 ABC 农村新闻和 ABC 科学新闻(`nltk.corpus.abc`)。使用 Punkt 处理句子分割。 +40. ★ 获取两个或多个文体的原始文本,计算它们各自的在前面关于阅读难度的练习中描述的阅读难度得分。例如,比较 ABC 农村新闻和 ABC 科学新闻(`nltk.corpus.abc`)。使用`Punkt`处理句子分割。 41. ★ 将下面的嵌套循环重写为嵌套列表推导: - > ```py - > >>> words = ['attribution', 'confabulation', 'elocution', - > ... 'sequoia', 'tenacious', 'unidirectional'] - > >>> vsequences = set() - > >>> for word in words: - > ... vowels = [] - > ... for char in word: - > ... if char in 'aeiou': - > ... vowels.append(char) - > ... vsequences.add(''.join(vowels)) - > >>> sorted(vsequences) - > ['aiuio', 'eaiou', 'eouio', 'euoia', 'oauaio', 'uiieioa'] - > ``` - -42. ★ 使用 WordNet 为一个文本集合创建语义索引。扩展例 3.6 中的一致性搜索程序,使用它的第一个同义词集偏移索引每个词,例如`wn.synsets('dog')[0].offset`offset(或者使用上位词层次中的一些祖先的偏移,这是可选的)。 + ```py + >>> words = ['attribution', 'confabulation', 'elocution', + ... 'sequoia', 'tenacious', 'unidirectional'] + >>> vsequences = set() + >>> for word in words: + ... vowels = [] + ... for char in word: + ... if char in 'aeiou': + ... vowels.append(char) + ... vsequences.add(''.join(vowels)) + >>> sorted(vsequences) + ['aiuio', 'eaiou', 'eouio', 'euoia', 'oauaio', 'uiieioa'] + ``` + +42. ★ 使用 WordNet 为一个文本集合创建语义索引。扩展例 3.6 中的一致性搜索程序,使用它的第一个同义词集偏移索引每个词,例如`wn.synsets('dog')[0].offset`(或者使用上位词层次中的一些祖先的偏移,这是可选的)。 43. ★ 在多语言语料库如世界人权宣言语料库(`nltk.corpus.udhr`),和 NLTK 的频率分布和关系排序的功能(`nltk.FreqDist`, `nltk.spearman_correlation`)的帮助下,开发一个系统,猜测未知文本。为简单起见,使用一个单一的字符编码和少几种语言。 diff --git a/4.md b/4.md index 22faf7db0e75a381853a78f809377fc82ad235fa..b24829a1f4d53480761908e28e0d643891eecc06 100644 --- a/4.md +++ b/4.md @@ -918,7 +918,7 @@ Python 提供一些具有函数式编程语言如 Haskell 标准特征的高阶 小心! -如果你的程序将使用大量的文件,它是一个好主意来关闭任何一旦不再需要的已经打开的文件。如果你使用`with`语句,Python 会自动关闭打开的文件︰ +如果你的程序将使用大量的文件,它是一个好主意来关闭任何一旦不再需要的已经打开的文件。如果你使用`with`语句,Python 会自动关闭打开的文件: ```py >>> with open("lexicon.txt") as f: diff --git a/5.md b/5.md index c5400681cba58cdc1ccb2b013d49ec777729bfba..875cecc6c3984ceaf5d6475f53e0d384ca8e180f 100644 --- a/5.md +++ b/5.md @@ -803,7 +803,7 @@ Python 字典方法:常用的方法与字典相关习惯用法的总结。 0.20326391789486245 ``` -最终的正则表达式«`.*`»是一个全面捕捉的,标注所有词为名词。这与默认标注器是等效的(只是效率低得多)。除了作为正则表达式标注器的一部分重新指定这个,有没有办法结合这个标注器和默认标注器呢?我们将很快看到如何做到这一点。 +最终的正则表达式`.*`是一个全面捕捉的,标注所有词为名词。这与默认标注器是等效的(只是效率低得多)。除了作为正则表达式标注器的一部分重新指定这个,有没有办法结合这个标注器和默认标注器呢?我们将很快看到如何做到这一点。 注意 diff --git a/9.md b/9.md index 638eeefd7741831cb8d965f79db218ede2abcf22..6f3955e2796ed08d77137dbe2acd6cd35ecd332b 100644 --- a/9.md +++ b/9.md @@ -159,7 +159,7 @@ V[TENSE=pres, -AUX] -> 'likes' 在传递中,我们应该指出有显示 AVM 的替代方法;1.3 显示了一个例子。虽然特征结构呈现的[(16)](./ch09.html#ex-agr0)中的风格不太悦目,我们将坚持用这种格式,因为它对应我们将会从 NLTK 得到的输出。 -关于表示,我们也注意到特征结构,像字典,对特征的*顺序*没有指定特别的意义。所以[(16)](./ch09.html#ex-agr0)等同于︰ +关于表示,我们也注意到特征结构,像字典,对特征的*顺序*没有指定特别的意义。所以[(16)](./ch09.html#ex-agr0)等同于: ```py [AGR = [NUM = pl ]]