比较python中字符串的最快方法

时间:2010-01-13 02:11:49

标签: python regex parsing

我正在用Python编写一个脚本,允许用户输入一个字符串,该字符串将指示脚本执行特定操作。为了争论,我会说我的命令列表是:

lock
read
write
request
log

现在,我希望用户能够输入单词“log”,它将执行特定操作,这非常简单。但是,我想匹配部分词。因此,例如,如果用户输入“lo”,它应该匹配“lock”,因为它在列表中更高。我已经尝试过使用ctypes从libc中使用strncmp来实现这个目标,但还没有做出正面或反面。

10 个答案:

答案 0 :(得分:16)

如果您接受用户的输入,那么为什么您担心比较的速度?即使是最慢的技术也会比用户能够察觉的快得多。使用最简单,最易理解的代码,并将效率问题留给紧密的内循环。

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]

答案 1 :(得分:5)

这将做你想要的:

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”并在他们认为“请求”时获得“读取”而导致的问题。最大限度地减少用户击键的风险是20世纪60年代,这是不好笑的。他们在用什么? ASR33电传?至少你可以坚持一个独特的匹配 - “rea”用于阅读,“req”用于请求。

答案 2 :(得分:3)

这在运行时就像您要求的那样进行了优化...... (尽管很可能不需要)

这是一段简单的代码,它将命令的输入字典映射到函数,并生成映射到同一函数的所有非重复子命令的输出字典。

所以当你启动服务时运行它,然后你有100%优化的查找。我确信有更聪明的方法可以做到这一点,所以随时编辑。

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,
}

答案 3 :(得分:2)

你可以使用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

答案 4 :(得分:2)

我建议你看一下使用readline python库,而不是重新发明轮子。 用户必须按Tab键才能完成单词,但您可以设置readline,以便选项卡尽可能匹配,或者循环显示以当前存根开头的所有单词。

这似乎是对python http://www.doughellmann.com/PyMOTW/readline/index.html

中readline的相当不错的介绍

答案 5 :(得分:1)

<{3}}中的{p> jaro_winkler()可能就是你要找的东西。

答案 6 :(得分:0)

替换为您喜欢的字符串比较功能。相当快,而且非常重要。

matches = ( x for x in list if x[:len(stringToSearchFor)] == stringToSearchFor )
print matches[0]

答案 7 :(得分:0)

这是改编自J.Tauber's Trie implementation in Python,您可以与所需的任何额外功能进行比较和/或重新调整。另请参阅Wikipedia entry on tries

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')
>>>

答案 8 :(得分:0)

如果我正确理解了您的问题,那么您需要一个能够尽快返回答案的代码段,而无需通过“命令列表”进一步遍历。这应该做你想要的:

from itertools import ifilter

def check_input(some_string, code_book) :
    for q in ifilter(code_book.__contains__, some_string) :
        return True
    return False

答案 9 :(得分:0)

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

所以基本上,根据我的评论,你问的是如何优化不需要测量时间或CPU的操作。我在这里使用了10,000个命令,测试字符串与每个命令匹配只是为了表明即使在极端情况下你仍然可以有数百个用户这样做,他们永远不会看到任何延迟。