我正在用Python编写一个脚本,允许用户输入一个字符串,这个字符串是一条指令,指示脚本执行特定的操作。举个例子,我会列出我的指令列表:
lock
read
write
request
log
现在,我希望用户能够输入单词“log”,然后进行特定的操作,这非常简单。但是,我希望能够匹配部分单词。例如,如果用户输入“lo”,它应该匹配“lock”,因为它在列表中更高。我尝试使用ctypes从libc中的strncmp来完成这个任务,但是我还没有搞清楚。
我正在用Python编写一个脚本,允许用户输入一个字符串,这个字符串是一条指令,指示脚本执行特定的操作。举个例子,我会列出我的指令列表:
lock
read
write
request
log
现在,我希望用户能够输入单词“log”,然后进行特定的操作,这非常简单。但是,我希望能够匹配部分单词。例如,如果用户输入“lo”,它应该匹配“lock”,因为它在列表中更高。我尝试使用ctypes从libc中的strncmp来完成这个任务,但是我还没有搞清楚。
如果你正在接受用户输入,那么为什么要担心比较速度?即使是最慢的技术也比用户感知到的要快得多。使用最简单易懂的代码,并将效率问题留给紧密的内部循环。
cmds = [
"lock",
"read",
"write",
"request",
"log",
]
def match_cmd(s):
matched = [c for c in cmds if c.startswith(s)]
if matched:
return matched[0]
def select_command(commands, user_input):
user_input = user_input.strip().lower()
for command in commands:
if command.startswith(user_input):
return command
return None
然而:
你似乎过于担心了错误的事情。因此,50个用户意味着50毫秒的延迟 - 您不会因这种“滞后”而被开除。要担心的是低效的数据库访问或由用户输入“r”并得到“read”而他们以为会得到“request”引起的问题。在冒险出错的情况下最小化用户击键,这种做法早已过时。他们使用的是什么?ASR33电传打字机吗?至少您可以坚持唯一匹配 - “rea”表示read,“req”表示request。
commands = {
'log': log_function,
'exit': exit_function,
'foo': foo_function,
'line': line_function,
}
cmap = {}
kill = set()
for command in commands:
for pos in range(len(1,command)):
subcommand = command[0:pos]
if subcommand in cmap:
kill.add(subcommand)
del(cmap[subcommand])
if subcommand not in kill:
cmap[subcommand] = commands[command]
#cmap now is the following - notice the duplicate prefixes removed?
{
'lo': log_function,
'log': log_function,
'e': exit_function,
'ex': exit_function,
'exi': exit_function,
'exit': exit_function,
'f' : foo_function,
'fo' : foo_function,
'foo' : foo_function,
'li' : line_function,
'lin' : line_function,
'line' : line_function,
}
您可以使用startswith函数。
例如:
myword = "lock"
if myword.startswith("lo"):
print "ok"
如果您想查找单词中的“lo”,而不考虑位置,请使用“in”运算符
if "lo" in myword
for cmd in ["lock","read","write","request","log"]:
if cmd.startswith(userinput):
print cmd
break
class Trie:
def __init__(self):
self.root = [None, {}]
def add(self, key):
curr_node = self.root
for ch in key:
curr_node = curr_node[1].setdefault(ch, [key, {}])
curr_node[0] = key
def find(self, key):
curr_node = self.root
for ch in key:
try:
curr_node = curr_node[1][ch]
except KeyError:
return None
return curr_node[0]
设置(添加顺序很重要!):
t = Trie()
for word in [
'lock',
'read',
'write',
'request',
'log']:
t.add(word)
然后像这样调用:
>>> t.find('lo')
'lock'
>>> t.find('log')
'log'
>>> t.find('req')
'request'
>>> t.find('requiem')
>>>
from itertools import ifilter
def check_input(some_string, code_book) :
for q in ifilter(code_book.__contains__, some_string) :
return True
return False
import timeit
cmds = []
for i in range(1,10000):
cmds.append("test")
def get_cmds(user_input):
return [c for c in cmds if c.startswith(user_input)]
if __name__=='__main__':
t = timeit.Timer("get_cmds('te')", "from __main__ import get_cmds")
print "%0.3f seconds" % (t.timeit(number=1))
#>>> 0.008 seconds
使用你最喜欢的字符串比较函数进行替换。相当快速,且简洁明了。
matches = ( x for x in list if x[:len(stringToSearchFor)] == stringToSearchFor )
print matches[0]
http://docs.python.org/library/stdtypes.html#str.startswith
(2) 不要使用list
,它会掩盖内置的list()
函数。 - John Machin