3.12 练习
☼ 定义一个字符串
s = 'colorless'
。写一个 Python 语句将其变为“colourless”,只使用切片和连接操作。☼ 我们可以使用切片符号删除词汇形态上的结尾。例如,
'dogs'[:-1]
删除了dogs
的最后一个字符,留下dog
。使用切片符号删除下面这些词的词缀(我们插入了一个连字符指示词缀的边界,请在你的字符串中省略掉连字符):dish-es
,run-ning
,nation-ality
,un-do
,pre-heat
。☼ 我们看到如何通过索引超出一个字符串的末尾产生一个
IndexError
。构造一个向左走的太远走到字符串的前面的索引,这有可能吗?☼ 我们可以为分片指定一个“步长”。下面的表达式间隔一个字符返回一个片内字符:
monty[6:11:2]
。也可以反向进行:monty[10:5:-2]
。自己尝试一下,然后实验不同的步长。☼ 如果你让解释器处理
monty[::-1]
会发生什么?解释为什么这是一个合理的结果。☼ 说明以下的正则表达式匹配的字符串类。
[a-zA-Z]+
[A-Z][a-z]*
p[aeiou]{,2}t
\d+(\.\d+)?
([^aeiou][aeiou][^aeiou])*
\w+|[^\w\s]+
使用
nltk.re_show()
测试你的答案。☼ 写正则表达式匹配下面字符串类:
> 1. 一个单独的限定符(假设只有 a, an 和 the 为限定符)。
> 2. 整数加法和乘法的算术表达式,如2*3+8
。☼ 写一个工具函数以 URL 为参数,返回删除所有的 HTML 标记的 URL 的内容。使用
from urllib import request
和request.urlopen('http://nltk.org/').read().decode('utf8')
来访问 URL 的内容。☼ 将一些文字保存到文件
corpus.txt
。定义一个函数load(f)
以要读取的文件名为其唯一参数,返回包含文件中文本的字符串。- 使用
nltk.regexp_tokenize()
创建一个分词器分割这个文本中的各种标点符号。使用一个多行的正则表达式,使用 verbose 标志(?x)
带有行内注释。 - 使用
nltk.regexp_tokenize()
创建一个分词器分割以下几种表达式:货币金额;日期;个人和组织的名称。
- 使用
☼ 将下面的循环改写为列表推导:
>>> sent = ['The', 'dog', 'gave', 'John', 'the', 'newspaper']
>>> result = []
>>> for word in sent:
... word_len = (word, len(word))
... result.append(word_len)
>>> result
[('The', 3), ('dog', 3), ('gave', 4), ('John', 4), ('the', 3), ('newspaper', 9)]
☼ 定义一个字符串
raw
包含你自己选择的句子。现在,以空格以外的其它字符例如's'
分割raw
。☼ 写一个
for
循环输出一个字符串的字符,每行一个。☼ 在字符串上调用不带参数的
split
与以' '
作为参数的区别是什么,即sent.split()
与sent.split(' ')
相比?当被分割的字符串包含制表符、连续的空格或一个制表符与空格的序列会发生什么?(在 IDLE 中你将需要使用'\t'
来输入制表符。)☼ 创建一个变量
words
,包含一个词列表。实验words.sort()
和sorted(words)
。它们有什么区别?☼ 通过在 Python 提示符输入以下表达式,探索字符串和整数的区别:
"3" * 7
和3 * 7
。尝试使用int("3")
和str(3)
进行字符串和整数之间的转换。☼ 使用文本编辑器创建一个文件
prog.py
,包含单独的一行monty = 'Monty Python'
。接下来,打开一个新的 Python 会话,并在提示符下输入表达式monty
。你会从解释器得到一个错误。现在,请尝试以下代码(注意你要丢弃文件名中的.py
):>>> from prog import monty
>>> monty
这一次,Python 应该返回一个值。你也可以尝试
import prog
,在这种情况下,Python 应该能够处理提示符处的表达式prog.monty
。☼ 格式化字符串
%6s
与%-6s
用来显示长度大于 6 个字符的字符串时,会发生什么?◑ 阅读语料库中的一些文字,为它们分词,输出其中出现的所有 wh-类型词的列表。(英语中的 wh-类型词被用在疑问句,关系从句和感叹句:who, which, what 等。)按顺序输出它们。在这个列表中有因为有大小写或标点符号的存在而重复的词吗?
◑ 创建一个文件,包含词汇和(任意指定)频率,其中每行包含一个词,一个空格和一个正整数,如
fuzzy 53
。使用open(filename).readlines()
将文件读入一个 Python 列表。接下来,使用split()
将每一行分成两个字段,并使用int()
将其中的数字转换为一个整数。结果应该是一个列表形式:[['fuzzy', 53], ...]
。◑ 编写代码来访问喜爱的网页,并从中提取一些文字。例如,访问一个天气网站,提取你所在的城市今天的最高温度预报。
◑ 写一个函数
unknown()
,以一个 URL 为参数,返回一个那个网页出现的未知词列表。为了做到这一点,请提取所有由小写字母组成的子字符串(使用re.findall()
),并去除所有在 Words 语料库(nltk.corpus.words
)中出现的项目。尝试手动分类这些词,并讨论你的发现。◑ 使用上面建议的正则表达式处理网址
http://news.bbc.co.uk/
,检查处理结果。你会看到那里仍然有相当数量的非文本数据,特别是 JavaScript 命令。你可能还会发现句子分割没有被妥善保留。定义更深入的正则表达式,改善此网页文本的提取。◑ 你能写一个正则表达式以这样的方式来分词吗,将词 don’t 分为 do 和 n’t?解释为什么这个正则表达式无法正常工作:«
n't|\w+
»。◑ 尝试编写代码将文本转换成 hAck3r,使用正则表达式和替换,其中
e
→3
,i
→1
,o
→0
,l
→|
,s
→5
,.
→5w33t!
,ate
→8
。在转换之前将文本规范化为小写。自己添加更多的替换。现在尝试将s
映射到两个不同的值:词开头的s
映射为`◑ Pig Latin 是英语文本的一个简单的变换。文本中每个词的按如下方式变换:将出现在词首的所有辅音(或辅音群)移到词尾,然后添加 ay,例如 string → ingstray, idle → idleay。
http://en.wikipedia.org/wiki/Pig_Latin
- 写一个函数转换一个词为 Pig Latin。
- 写代码转换文本而不是单个的词。
- 进一步扩展它,保留大写字母,将
qu
保持在一起(例如这样quiet
会变成ietquay
),并检测y
是作为一个辅音(如yellow
)还是一个元音(如style
)。
◑ 下载一种包含元音和谐的语言(如匈牙利语)的一些文本,提取词汇的元音序列,并创建一个元音二元语法表。
◑ Python 的
random
模块包括函数choice()
,它从一个序列中随机选择一个项目,例如choice("aehh ")
会产生四种可能的字符中的一个,字母h
的几率是其它字母的两倍。写一个表达式产生器,从字符串"aehh "
产生 500 个随机选择的字母的序列,并将这个表达式写入函数''.join()
调用中,将它们连接成一个长字符串。你得到的结果应该看起来像失去控制的喷嚏或狂笑:he haha ee heheeh eha
。使用split()
和join()
再次规范化这个字符串中的空格。◑ 考虑下面的摘自 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”?或者我们应该说这不是一个“真正的”词,因为它不会出现在任何词典中?讨论这些不同的可能性。你能想出产生这些答案中至少两个以上可能性的应用领域吗?
◑ 可读性测量用于为一个文本的阅读难度打分,给语言学习者挑选适当难度的文本。在一个给定的文本中,让我们定义μ<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()
产生一个句子的序列的事实。◑ 使用 Porter 词干提取器规范化一些已标注的文本,对每个词调用提取词干器。用 Lancaster 词干提取器做同样的事情,看看你是否能观察到一些差别。
◑ 定义变量
saying
包含列表['After', 'all', 'is', 'said', 'and', 'done', ',', 'more', 'is', 'said', 'than', 'done', '.']
。使用for
循环处理这个列表,并将结果存储在一个新的链表lengths
中。提示:使用lengths = []
,从分配一个空列表给lengths
开始。然后每次循环中用append()
添加另一个长度值到列表中。现在使用列表推导做同样的事情。◑ 定义一个变量
silly
包含字符串:'newly formed bland ideas are inexpressible in an infuriating way'
。(这碰巧是合法的解释,讲英语西班牙语双语者可以适用于乔姆斯基著名的无意义短语,colorless green ideas sleep furiously,来自维基百科)。编写代码执行以下任务:- 分割
silly
为一个字符串列表,每一个词一个字符串,使用 Python 的split()
操作,并保存到叫做bland
的变量中。 - 提取
silly
中每个词的第二个字母,将它们连接成一个字符串,得到'eoldrnnnna'
‘。 - 使用
join()
将bland
中的词组合回一个单独的字符串。确保结果字符串中的词以空格隔开。 - 按字母顺序输出
silly
中的词,每行一个。
- 分割
◑
index()
函数可用于查找序列中的项目。例如,'inexpressible'.index('e')
告诉我们字母e
的第一个位置的索引值。- 当你查找一个子字符串会发生什么,如
'inexpressible'.index('re')
? - 定义一个变量
words
,包含一个词列表。现在使用words.index()
来查找一个单独的词的位置。 - 定义上一个练习中的变量
silly
。使用index()
函数结合列表切片,建立一个包括silly
中in
之前(但不包括)的所有的词的列表phrase
。
- 当你查找一个子字符串会发生什么,如
◑ 编写代码,将国家的形容词转换为它们对应的名词形式,如将 Canadian 和 Australian 转换为 Canada 和 Australia(见
http://en.wikipedia.org/wiki/List_of_adjectival_forms_of_place_names
)。◑ 阅读 LanguageLog 中关于短语的 as best as p can 和 as best p can 形式的帖子,其中 p 是一个代名词。在一个语料库和3.5中描述的搜索已标注的文本的
findall()
方法的帮助下,调查这一现象。http://itre.cis.upenn.edu/~myl/languagelog/archives/002733.html
◑ 研究《创世记》的 lolcat 版本,使用
nltk.corpus.genesis.words('lolcat.txt')
可以访问,和http://www.lolcatbible.com/index.php?title=How_to_speak_lolcat
上将文本转换为 lolspeak 的规则。定义正则表达式将英文词转换成相应的 lolspeak 词。◑ 使用
help(re.sub)
和参照本章的深入阅读,阅读有关re.sub()
函数来使用正则表达式进行字符串替换。使用re.sub
编写代码从一个 HTML 文件中删除 HTML 标记,规范化空格。★ 分词的一个有趣的挑战是已经被分割的跨行的词。例如如果 long-term 被分割,我们就得到字符串
long-\nterm
。- 写一个正则表达式,识别连字符连结的跨行处的词汇。这个表达式将需要包含
\n
字符。 - 使用
re.sub()
从这些词中删除\n
字符。 - 你如何确定一旦换行符被删除后不应该保留连字符的词汇,如
'encyclo-\npedia'
?
- 写一个正则表达式,识别连字符连结的跨行处的词汇。这个表达式将需要包含
★ 阅读维基百科 Soundex 条目。用 Python 实现这个算法。
★ 获取两个或多个文体的原始文本,计算它们各自的在前面关于阅读难度的练习中描述的阅读难度得分。例如,比较 ABC 农村新闻和 ABC 科学新闻(
nltk.corpus.abc
)。使用 Punkt 处理句子分割。★ 将下面的嵌套循环重写为嵌套列表推导:
>
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'] >
★ 使用 WordNet 为一个文本集合创建语义索引。扩展例3.6中的一致性搜索程序,使用它的第一个同义词集偏移索引每个词,例如
wn.synsets('dog')[0].offset
offset(或者使用上位词层次中的一些祖先的偏移,这是可选的)。★ 在多语言语料库如世界人权宣言语料库(
nltk.corpus.udhr
),和 NLTK 的频率分布和关系排序的功能(nltk.FreqDist
,nltk.spearman_correlation
)的帮助下,开发一个系统,猜测未知文本。为简单起见,使用一个单一的字符编码和少几种语言。★ 写一个程序处理文本,发现一个词以一种新的意义被使用的情况。对于每一个词计算这个词所有同义词集与这个词的上下文的所有同义词集之间的 WordNet 相似性。(请注意,这是一个粗略的办法;要做的很好是困难的,开放性研究问题。)
★ 阅读关于规范化非标准词的文章(Sproat et al, 2001),实现一个类似的文字规范系统。
关于本文档…
针对 NLTK 3.0 作出更新。本章来自于 Natural Language Processing with Python,Steven Bird, Ewan Klein 和Edward Loper,Copyright © 2014 作者所有。本章依据 Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License [http://creativecommons.org/licenses/by-nc-nd/3.0/us/] 条款,与 自然语言工具包 [http://nltk.org/
] 3.0 版一起发行。
本文档构建于星期三 2015 年 7 月 1 日 12:30:05 AEST