首页 > 程序开发 > Web开发 > Python >

Learn Python The Hard Way学习(48) - 更高级的用户输入

2012-07-12

你的游戏可能已经做得不错了,但是用户输入很麻烦,每次都输入完全正确的字符才能执行命令,我们需要一个东西让用户可以输入不同的短语就可以执行命令,比如,你想要下面这些词语都能执行:open dooropen the ...

你的游戏可能已经做得不错了,但是用户输入很麻烦,每次都输入完全正确的字符才能执行命令,我们需要一个东西让用户可以输入不同的短语就可以执行命令,比如,你想要下面这些词语都能执行:
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的一个结构叫元组,元组其实就是一个不能修改的列表,用括号包含,逗号区分:
first_word = ('dirction', 'north')
second_word = ('verb', 'go')
sentence = [first_word, second_word]

我们创建了一组(TYPE, WORD),让你识别单词。

这只是一个例子,不过基本就是这样,你接受用户输入,使用split拆分句子,区分单词类型,然后重新组合。

扫描输入
现在开始写你的扫描器吧,这个扫描器取得用户输入,然后返回一个包括元组(TOKEN, WORD)的列表。如果不存在这样一个单词,还是应该返回WORD,但是TOKEN应该返回错误信息。

我不会告诉你具体的代码,而是写一个测试,你要确保测试能通过。

异常和数字
我会先帮你一个小忙,关于数字转换,我们使用异常,比如:
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> int("hell")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: &#39;hell&#39;
>>>

这个ValueError是int函数的异常,因为int需要一个数字参数。本来int()可以返回一个-1表示输入错误,但是-1也是整数,所以只能返回ValueError异常。

我们下面用try和except处理异常:
[python]
def convert_number(s):
try:
return int(s)
except ValueError:
return none


把执行代码放到try代码块中,错误返回放到except代码块中,这样发生错误的时候就可以返回none。

在扫描器中你要使用这个函数来测试输入的是不是一个数字。

测试文件 www.2cto.com
把下面的代码写入tests/lexicon_tests.py文件中。
[python]
from nose.tools import *
from ex48 import lexicon




def test_directions():
assert_equal(lexicon.scan("north"), [(&#39;direction&#39;, &#39;north&#39;)])
result = lexicon.scan("north south east")
assert_equal(result, [(&#39;direction&#39;, &#39;north&#39;),
(&#39;direction&#39;, &#39;south&#39;),
(&#39;direction&#39;, &#39;east&#39;)])


def test_verbs():
assert_equal(lexicon.scan("go"), [(&#39;verb&#39;, &#39;go&#39;)])
result = lexicon.scan("go kill eat")
assert_equal(result, [(&#39;verb&#39;, &#39;go&#39;),
(&#39;verb&#39;, &#39;kill&#39;),
(&#39;verb&#39;, &#39;eat&#39;)])




def test_stops():
assert_equal(lexicon.scan("the"), [(&#39;stop&#39;, &#39;the&#39;)])
result = lexicon.scan("the in of")
assert_equal(result, [(&#39;stop&#39;, &#39;the&#39;),
(&#39;stop&#39;, &#39;in&#39;),
(&#39;stop&#39;, &#39;of&#39;)])




def test_nouns():
assert_equal(lexicon.scan("bear"), [(&#39;noun&#39;, &#39;bear&#39;)])
result = lexicon.scan("bear princess")
assert_equal(result, [(&#39;noun&#39;, &#39;bear&#39;),
(&#39;noun&#39;, &#39;princess&#39;)])


def test_numbers():
assert_equal(lexicon.scan("1234"), [(&#39;number&#39;, 1234)])
result = lexicon.scan("3 91234")
assert_equal(result, [(&#39;number&#39;, 3),
(&#39;number&#39;, 91234)])




def test_errors():
assert_equal(lexicon.scan("ASDFADFASDF"), [(&#39;error&#39;, &#39;ASDFADFASDF&#39;)])
result = lexicon.scan("bear IAS princess")
assert_equal(result, [(&#39;noun&#39;, &#39;bear&#39;),
(&#39;error&#39;, &#39;IAS&#39;),
(&#39;noun&#39;, &#39;princess&#39;)])


记得新建一个项目来完成这些代码。

设计提示
集中实现一个测试工作。尽量简单的把所有的单词放到lexicon列表中。不要修改输入列表,你要做的是创建你自己的元组。使用in来判断单词是否在字典中。

加分练习
1. 改进测试用例,让它可以判断更多单词。
2. 添加字典,更新测试用例。
3. 让你的扫描器能识别大写,更新测试用例。
4. 寻找其他数字转换的方法。
5. 我的代码只有37行,你的呢?


作者:lixiang0522
相关文章
最新文章
热点推荐