习题 48: 更复杂的用户输入¶

你的游戏可能一路跑得很爽,不过你处理用户输入的方式肯定让你不胜其烦了。每一个房间都需要一套自己的语句,而且只有用户完全输入正确后才能执行。你需要一个设备,它可以允许用户以各种方式输入语汇。例如下面的机种表述都应该被支持才对:

open door

open the door

go THROUGH the door

punch bear

Punch The Bear in the FACE

也就是说,如果用户的输入和常用英语很接近也应该是可以的,而你的游戏要识别出它们的意思。为了达到这个目的,我们将写一个模组专门做这件事情。这个模组里边会有若干个类,它们互相配合,接受用户输入,并且将用户输入转换成你的游戏可以识别的命令。

英语的简单格式是这个样子的:

单词由空格隔开。

句子由单词组成。

语法控制句子的含义。

所以最好的开始方式是先搞定如何得到用户输入的词汇,并且判断出它们是什么。

我们的游戏语汇¶

我在游戏里创建了下面这些语汇:

表示方向: north, south, east, west, down, up, left, right, back.

动词: go, stop, kill, eat.

修饰词: the, in, of, from, at, it

名词: door, bear, princess, cabinet.

数词: 由 0-9 构成的数字。

说到名词,我们会碰到一个小问题,那就是不一样的房间会用到不一样的一组名词,不过让我们先挑一小组出来写程序,以后再做改进把。

如何断句¶

我们已经有了词汇表,为了分析句子的意思,接下来我们需要找到一个断句的方法。我们对于句子的定义是“空格隔开的单词”,所以只要这样就可以了:

stuff = raw_input("> ")

words = stuff.split()

目前做到这样就可以了,不过这招在相当一段时间内都不会有问题。

语汇元组¶

一旦我们知道了如何将句子转化成词汇列表,剩下的就是逐一检查这些词汇,看它们是什么类型。为了达到这个目的,我们将用到一个非常好使的 Python 数据结构,叫做”元组(tuple)”。元组其实就是一个不能修改的列表。创建它的方法和创建列表差不多,成员之间需要用逗号隔开,不过方括号要换成圆括号 () :

first_word = ("direction", "north")

second_word = ("verb", "go")

sentence = [first_word, second_word]

这样我们就创建了一个 (TYPE, WORD) 组,让你识别出单词,并且对它执行指令。

这只是一个例子,不过最后做出来的样子也差不多。你接受用户输入,用 split

将其分隔成单词列表,然后分析这些单词,识别它们的类型,最后重新组成一个句子。

扫描输入¶

现在你要写的是词汇扫描器。这个扫描器会将用户的输入字符串当做参数,然后返回由多个 (TOKEN, WORD) 组成的一个列表,这个列表实现类似句子的功能。如果一个单词不在预定的词汇表中,那它返回时 WORD 应该还在,但 TOKEN 应该设置成一个专门的错误标记。这个错误标记将告诉用户哪里出错了。

有趣的地方来了。我不会告诉你这些该怎样做,但我会写一个“单元测试(unit test)”,而你要把扫描器写出来,并保证单元测试能够正常通过。

“异常”和数字¶

有一件小事情我会先帮帮你,那就是数字转换。为了做到这一点,我们会作一点弊,使用“异常(exceptions)”来做。“异常”指的是你运行某个函数时得到的错误。你的函数在碰到错误时,就会“提出(raise)”一个“异常”,然后你就要去处理(handle)这个异常。假如你在Python 里写了这些东西:

~/projects/simplegame $ python

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)

[GCC 4.4.3] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>>int("hell")

Traceback (most recent call last):

File "", line 1, in

ValueError: invalid literal for int() with base 10: "hell"

>>

这个 ValueError 就是 int() 函数抛出的一个异常。因为你给 int() 的参数不是一个数字。 int() 函数其实也可以返回一个值来告诉你它碰到了错误,不过由于它只能返回整数值,所以很难做到这一点。它不能返回 -1,因为这也是一个数字。

int() 没有纠结在它“究竟应该返回什么”上面,而是提出了一个叫做 ValueError

的异常,然后你只要处理这个异常就可以了。

处理异常的方法是使用 try 和 except 这两个关键字:

def convert_number(s):

try:

return int(s)

except ValueError:

return None

你把要试着运行的代码放到 try 的区段里,再将出错后要运行的代码放到 except

区段里。在这里,我们要试着调用 int() 去处理某个可能是数字的东西,如果中间出了错,我们就抓到这个错误,然后返回 None。

在你写的扫描器里面,你应该使用这个函数来测试某个东西是不是数字。做完这个检查,你就可以声明这个单词是一个错误单词了。

你应该测试的东西¶

这里是你应该使用的测试文件 tests/lexicon_tests.py :

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46from nose.tools import *

from ex48 import lexicon

def test_directions():

assert_equal(lexicon.scan("north"), [("direction", "north")])

result = lexicon.scan("north south east")

assert_equal(result, [("direction", "north"),

("direction", "south"),

("direction", "east")])

def test_verbs():

assert_equal(lexicon.scan("go"), [("verb", "go")])

result = lexicon.scan("go kill eat")

assert_equal(result, [("verb", "go"),

("verb", "kill"),

("verb", "eat")])

def test_stops():

assert_equal(lexicon.scan("the"), [("stop", "the")])

result = lexicon.scan("the in of")

assert_equal(result, [("stop", "the"),

("stop", "in"),

("stop", "of")])

def test_nouns():

assert_equal(lexicon.scan("bear"), [("noun", "bear")])

result = lexicon.scan("bear princess")

assert_equal(result, [("noun", "bear"),

("noun", "princess")])

def test_numbers():

assert_equal(lexicon.scan("1234"), [("number", 1234)])

result = lexicon.scan("3 91234")

assert_equal(result, [("number", 3),

("number", 91234)])

def test_errors():

assert_equal(lexicon.scan("ASDFADFASDF"), [("error", "ASDFADFASDF")])

result = lexicon.scan("bear IAS princess")

assert_equal(result, [("noun", "bear"),

("error", "IAS"),

("noun", "princess")])

记住你要使用你的项目骨架来创建新项目,将这个测试用例写下来(不许复制粘贴!),然后编写你的扫描器,直至所有的测试都能通过。注意细节并确认结果一切工作良好。

设计的技巧¶

集中一次实现一个测试项目,尽量保持项目简单,只要把你的 lexicon.py 词汇表中所有的单词放那里就可以了。不要修改输入的单词表,不过你需要创建自己的新列表,里边包含你的语汇元组。另外,记得使用 in 关键字来检查这些语汇列表,以确认某个单词是否在你的语汇表中。

加分习题¶

改进单元测试,让它覆盖到更多的语汇。

向语汇列表添加更多的语汇,并且更新单元测试代码。

让你的扫描器能够识别任意大小写的词汇。更新你的单元测试以确认其功能。

找出另外一种转换为数字的方法。

我的解决方案用了 37 行代码,你的是更长还是更短呢?

python输入print跳到documentation-习题 48: 更复杂的用户输入相关推荐

  1. 用户输入邮箱,验证邮箱格式是否正确(验证用户输入的邮箱地址中是否含有字符'@')

    要求:用户输入邮箱,验证邮箱格式是否正确(验证用户输入的邮箱地址中是否含有字符'@'). 目的:掌握邮箱验证控件的原理和方法. #include<stdio.h> #include< ...

  2. 《Python编程从入门到实践》学习笔记7:用户输入和while循环

    一.用户输入 函数input()的功能,就是让程序在运行过程中,能够接收到用户的输入进行输出,如下例所示: prompt = "请按照提示输入您的姓名,我们将根据您的姓名显示信息!\n&qu ...

  3. python自定义函数实例计算1-n的偶偶数和_python用户输入一个整数N,计算并输出1到N相加的和,请问这个程序错在哪里了?...

    展开全部 第一个错误的地方是for i in str(n),input()输入的是636f707962616964757a686964616f31333431356661整型,循环增加应该用for i ...

  4. python用户输入若干个分数_编写一个程序,要求用户输入五个测试分数。与字母grad对应...

    Determine_grade-接受单个数字作为参数,并根据以下评分标准显示分数的字母等级:Score 90-100 80-89 70-79 60-69 Below 60 Letter Grade A ...

  5. 谷歌浏览器百度搜索引擎输入后跳转到百度首页并且会吞掉输入内容

    谷歌浏览器百度搜索引擎输入后跳转到百度首页且网址为https://www.baidu.com/?tn=78000241_45_hao_pg 今天电脑更新,打开谷歌浏览器搜索时给我跳转到百度首页,百度首 ...

  6. python等待用户输入指定秒_如何在10秒后强制用户输入

    我是一个python初学者,需要一些帮助来进行类似测验的游戏. 这是我的代码:import time from threading import Timer import random as rnd ...

  7. python输入输出字符串_在线等 python--编写下列程序。 用户输入一段字符串,输出该字符串的长度小写大写形式...

    import binascii # python>=3.7 str_in = input('请输入一个字符串:') print(f'长度:{len(str_in)}\n' f'大写:{str_i ...

  8. Python day1 变量、常量、注释基础数据类型初始以及用户输入input

    CPU:计算机的运算和计算中心,相当于人类的大脑. 内存:暂时存储数据,临时加载数据应用程序,速度快,断电即消失,造价很高. 硬盘:磁盘,长期存储数据,速度较慢,造价相对较低. 操作系统:一个软件,连 ...

  9. 【廖雪峰 python教程 课后题改编】利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字

    原题目: # -*- coding: utf-8 -*- #输入名字,变成首字母大写,其他字母小写的标准格式 def normalize(name):str1 = ''for i, ch in enu ...

最新文章

  1. 移动设备感染率及物联网设备安全漏洞数量创下历史新高
  2. 促使网站关键词排名稳定的技巧有哪些?
  3. 某小公司 RESTful、共用接口、前后端分离、接口约定的实践
  4. 4.mysql数据库创建,表创建模等模板脚本,mysql_SQL99标准的连接查询(内连接,外连接,满外连接,交叉连接)
  5. why my CREATE_OW will not generate OSSET entry in OB buffer
  6. python引入模块时import与from ... import的区别
  7. Spring Boot Actuator:在其顶部具有MVC层的自定义端点
  8. 【渝粤教育】广东开放大学 教育心理学 形成性考核 (42)
  9. 编译原理(简单自动词法分析器LEX)
  10. S5700日志查看与清空
  11. 使用嵌套循环,打印 5 行 5 列的直角三角形
  12. java调用ole ie_SWT中通过Automatioin的方式访问IE(升级版)
  13. MySQL 基础总结
  14. pyqt5 列表内添加按钮
  15. 学习ectouch之文件结构
  16. idea用token登陆github_Vue 页面权限控制和登陆验证
  17. 课程设计——模仿网易云UI设计基础(超简单版)
  18. 工业物联网·能耗监控智慧空调接入华为云解决方案
  19. 宝贝对不起,放下工作养不起你,拿起工作陪不了你…
  20. 《数据库系统概论》学习总结

热门文章

  1. tcga癌症亚型获取_将亚型多态性与通用多态性相关联的危险
  2. 日志消息是可执行代码和注释
  3. java 对象复活_Java对象复活
  4. 测试Java EE 8规范
  5. JMH:如何设置和运行JMH基准
  6. Hazelcast入门指南第5部分
  7. JDK 8中的流驱动的集合功能
  8. 需要微缓存吗? 营救记忆
  9. Java内存模型和优化
  10. ZK的实际应用:MVVM –以编程方式更新视图