《Think Python 2e》学习精粹(九): 文字游戏

《Think Python 2e》学习精粹(九): 文字游戏



1、读取单词列表

  • Grady Ward 收集并贡献给公众的单词列表:words.txt
  • 内建函数 open 接受文件名作为形参,并返回一个 文件对象(file object) ,可以使用它读取该文件,文件名即 python 运行目录 (本文实验环境 python 运行目录为 C:\Users\Administrator)中文件的文件名;
  • 该文件对象提供了几个读取方法, 包括 readline ,其从文件中读取字符直到碰到新行(即回车符),并将结果作为字符串返回;
>>> fin = open('words.txt')
>>> word = fin.readline()
>>> word
'aa\n'
  • 此文件对象跟踪它在文件中的位置, 所以如果你再次调用readline,获得下一个单词 ;
  • 可以用字符串方法 strip 删掉回车符 ‘\n’ ;
>>> word.strip()
'aa'
  • 可以将文件对象用做for循环的一部分;
fin = open('words.txt')
for line in fin:
	word = line.strip()
	if len(word) >= 20:
		print(word)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new42.py
counterdemonstration
counterdemonstrations
counterdemonstrators
hyperaggressivenesses
hypersensitivenesses
microminiaturization
microminiaturizations
representativenesses

2、练习

习题9-1:打印出长度超过20的单词

【习题 】 编程写一个程序,使得它可以读取 words.txt ,然后只打印出那些长度超过20个字符的单词(不包括空格)

  • 练习记录:
fin = open('words.txt')
for line in fin:
	word = line.strip()
	if len(word) > 20:
		print(word)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new42.py
counterdemonstrations
hyperaggressivenesses
microminiaturizations

习题9-2:寻找不包含字符“e”的单词

【习题 】 写一个叫做has_no_e的函数,如果给定的单词中不包含字符“e”,其返回 True ,修改上一节中的程序,只打印不包含“e”的单词,并且计算列表中不含“e”单词的比例

def has_no_e(word):
	for letter in word:
		if letter == 'e':
			return False
	return True

fin = open('words.txt')
m = 0
n = 0
for line in fin:
	word = line.strip()
	if len(word) > 20:
		if has_no_e(word):
			print(word)
			n = n+1
		m = m+1
per = n/m*100
print('per =',per)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new43.py
microminiaturizations
per = 33.33333333333333

习题9-3:寻找不包含字符串中字符的单词

【习题9.3 .1】 编写一个名为 avoids 的函数,接受一个单词和一个指定禁止使用字符的字符串, 如果单词中不包含任意被禁止的字符,则返回True ,修改你的程序,提示用户输入一个禁止使用的字符串,然后打印 words.txt 中不包含字符串中任一字符的单词的数量

  • 练习记录:
def avoids(word, str):
	for letter in word:
		for line in str:
			if letter == line:
				return False
	return True

fin = open('words.txt')
str = input('Please enter a string:')
x = 0
for line in fin:
	word = line.strip()
	if avoids(word, str):
		x = x+1
print(x)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new46.py
Please enter a string: hello
9552
  • 变形练习: 打印 words.txt 中不包含字母表各个字母的单词数量
def avoids(word, str):
	for letter in word:
		for line in str:
			if letter == line:
				return False
	return True
	
for i in range(26):
	str = chr(ord('a')+i)
	fin = open('words.txt')
	x = 0
	for line in fin:
		word = line.strip()
		if avoids(word, str):
			x = x+1									
	print(str,':', x)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new45.py
a : 57196
b : 97504
c : 83343
d : 83161
e : 37641
f : 102532
g : 88830
h : 94713
i : 53495
j : 112062
k : 104831
l : 73676
m : 91335
n : 64127
o : 69152
p : 90840
q : 112177
r : 58908
s : 49006
t : 66530
u : 84934
v : 104917
w : 105541
x : 111118
y : 100668
z : 110358

【习题9.3.2】 找到一个5个禁止使用字符的组合,使得其排除的单词数目最少

  • 练习记录:
def avoids(word, str):
	for letter in word:
		for line in str:
			if letter == line:
				return False
	return True

n = 0
string = ''	
for i in range(0, 26):
	for j in range(i+1, 26):
		for k in range(j+1, 26):
			for l in range(k+1, 26):
				for m in range(l+1,26):
					str = chr(ord('a')+i)+chr(ord('a')+j)+chr(ord('a')+k)+chr(ord('a')+l)+chr(ord('a')+m)
					print(str, end = ' : ')
					fin = open('words.txt')
					x = 0
					for line in fin:
						word = line.strip()
						if avoids(word, str):
							x = x+1
					print(x, end=' , ')
					if  x > n:
						n = x
						string = str
					print(n)
print(string, n)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new44.py
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new44.py
abcde : 7990 , 7990
abcdf : 22286 , 22286
abcdg : 18914 , 22286
abcdh : 21124 , 22286
abcdi : 10857 , 22286
abcdj : 25371 , 25371
abcdk : 23694 , 25371
……
uvxyz : 63733 , 96425
uwxyz : 63553 , 96425
vwxyz : 80593 , 96425
jqwxz 96425
  • 结果分析:由于本题练习所用算法是从字母表中的26个字母中取5个的组合组成一个字符串,共可以组合成 C526 = 65780 个不同的字符串,分别计算不含该字符串中字母的单词数量,然后找出数量最大的那个字符串,这个算法计算量太大,我把 shell 打开了第二天才看到结果:jqwxz 96425 ,不含 jqwxz 这个字符串中任一字母的单词最多(即排除最少),以后有更好的算法再改善,得到的结果其实从上题的变形练习就可以猜到

习题9-4:指定字母组词、造句

【习题】 编写一个名为uses_only的函数,接受一个单词和一个字符串。 如果该单词只包括此字符串中的字符,则返回True,你能只用 acefhlo 这几个字符造一个句子么? 除了“Hoe alfalfa”外

  • 练习记录:
def uses_only(word, str):
	for letter in word:
		a = False
		for line in str:
			if letter == line:
				a = True
		if a == False:
			return False
	return True
	
fin = open('words.txt')
for line in fin:
	word = line.strip()
	if uses_only(word, 'acefhlo'):
		print(word)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new50.py
aa
aah
aal
ace
ache
acho
……
olea
oleo
olla
ooh
  • 结果分析:程序结果罗列了所有仅由 acefhlo 这些字符组成的单词,至于用这些单词造句么,嘿嘿,我英语不好,似乎其中没有一个单词能看懂,造句就算了吧

习题9-5:包含指定的所有字符的单词

【习题】 编写一个名为uses_all的函数,接受一个单词和一个必须使用的字符组成的字符串。 如果该单词包括此字符串中的全部字符至少一次,则返回True, 你能统计出多少单词包含了所有的元音字符 aeiouy 吗?

def uses_all(word, str):
	for letter in str:
		if letter not in word:
			return False
	return True
	
fin = open('words.txt')
n = 0
for line in fin:
	word = line.strip()
	if uses_all(word, 'aeiouy'):
		n = n+1
		print(word)
print(n)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new52.py
abstemiously
adventitiously
aeronautically
……
unintentionally
unquestionably
42
  • 变形练习:
def uses_all(word, str):
	for letter in str:
		if letter in word:
			continue
		else:
			return False
	return True
	
  • 结果分析:对比上一题的代码,可以发现用 in 和 not in 两个布尔运算符能减少许多代码,且更直观和便于理解

习题9-6:字母以字母表程序出现的单词

【习题】 编写一个名为is_abecedarian的函数, 如果单词中的字符以字符表的顺序出现(允许重复字符),则返回True , 有多少个具备这种特征的单词?

  • 练习记录:
def is_abecedarian(word):
	i = 1
	for letter in word:
		for j in range(i, len(word)):
			if letter >= word[j]:
				if j == i and letter == word[j]:
					continue
				return False
		i = i+1
	return True
	
fin = open('words.txt')
n = 0
for line in fin:
	word = line.strip()
	if is_abecedarian(word):
		n = n+1
		print(n, word)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new55.py
1 aa
2 aah
3 aahs
4 aal
5 aals
……
592 oy
593 pry
594 psst
595 sty
596 tux
  • 结果分析:if j == i and letter == word[j]:语句的加入是为了允许有重复的字符出现

3、搜索

  • avoids;
def avoids(word, forbidden):
	for letter in word:
		if letter in forbidden:
			return False
	return True
  • uses_only;
def uses_only(word, available):
	for letter in word:
		if letter not in available:
			return False
	return True
  • 简化为之前已解决的问题(reduction to a previously solved problem)的程序开发方法的一个示例,也就是说,认识到当前面临的问题是之前已经解决的问题的一个实例, 然后应用了已有的解决方案:uses_all;
def uses_all(word, required):
	for letter in required:
		if letter not in word:
			return False
	return True
def uses_all(word, required):
	return uses_only(required, word)

4、使用索引进行循环

  • for 循环写 is_abecedarian;
def is_abecedarian(word):
	previous = word[0]
	for c in word:
		if c < previous:
			return False
		previous = c
	return True
  • 递归法写 is_abecedarian;
def is_abecedarian(word):
	if len(word) <= 1:
		return True
	if word[0] > word[1]:
		return False
	return is_abecedarian(word[1:])
  • while 循环写 is_abecedarian;
def is_abecedarian(word):
	i = 0
	while i < len(word)-1:
		if word[i+1] < word[i]:
			return False
		i = i+1
	return True
  • is_palindrome 函数的一种版本;
def is_palindrome(word):
	i = 0
	j = len(word)-1

	while i<j:
		if word[i] != word[j]:
			return False
		i = i+1
		j = j-1

	return True
  • is_palindrome 函数的另一种版本;
def is_palindrome(word):
	return is_reverse(word, word)

5、调试

  • 选择一可以测试所有可能错误的单词集合,是很困难的,介于困难和不可能之间;
  • 以 has_no_e为例,有两个明显的用例需要检查: 含有‘e’的单词应该返回 False ,不含的单词应该返回 True , 你应该可以很容易就能想到这两种情况;
  • 在每个用例中,还有一些不那么明显的子用例, 在含有“e”的单词中,你应该测试“e”在开始、结尾以及在中间的单词,你还应该测试长单词、短单词以及非常短的单词,如空字符串,空字符串是一个特殊用例(special case),及一个经常出现错误的不易想到的用例;
  • 除了自己生成的测试用例,也可以用一个类似 words.txt 中的单词列表测试你的程序, 通过扫描输出,可能会捕获错误,但是请注意: 可能捕获一类错误(包括了不应该包括的单词) 却没能捕获另一类错误(没有包括应该包括的单词);
  • 一位传奇计算机科学家—Edsger W. Dijkstra 所说:程序测试能用于展示错误的存在,但是无法证明不存在错误!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值