代码之家  ›  专栏  ›  技术社区  ›  Mike Trpcic

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

  •  8
  • Mike Trpcic  · 技术社区  · 15 年前

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

    lock
    read
    write
    request
    log
    

    现在,我希望用户能够输入单词“log”,它将形成一个特定的操作,这非常简单。但是,我想匹配部分单词。因此,例如,如果用户输入“lo”,它应该匹配“lock”,因为它在列表中较高。我已经尝试使用libc中的strncmp和ctypes来实现这一点,但还没有完全了解。

    10 回复  |  直到 15 年前
        1
  •  16
  •   Ned Batchelder    15 年前

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

    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]
    
        2
  •  5
  •   John Machin Santi    15 年前

    这将满足您的要求:

    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”并在认为会得到“请求”时得到“读取”所导致的问题。以出错的风险最大限度地减少用户击键,这一点都不好笑。他们在用什么?ASR33电传打字机?至少你可以坚持一个独特的匹配——“rea”表示读取,“req”表示请求。

        3
  •  3
  •   gahooa    15 年前

    (尽管很可能不需要)

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

    因此,当您启动服务时运行此程序,然后您就有了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,
    }
    
        4
  •  2
  •   ghostdog74    15 年前

    您可以使用startswith

    myword = "lock"
    if myword.startswith("lo"):
       print "ok"
    

    if "lo" in myword
    

    因此,有一种方法可以做到这一点:

    for cmd in ["lock","read","write","request","log"]:
        if cmd.startswith(userinput):
            print cmd
            break
    
        5
  •  2
  •   Michael Anderson    15 年前

    用户必须点击tab键才能完成单词,但您可以设置readline,以便tab键尽可能匹配,或者从当前存根开始遍历所有单词。

    这似乎是对python中readline的一个相当不错的介绍 http://www.doughellmann.com/PyMOTW/readline/index.html

        6
  •  1
  •   Ignacio Vazquez-Abrams    15 年前

    jaro_winkler() 在里面 python-Levenshtein 可能就是你要找的。

        7
  •  0
  •   Peter Hansen    15 年前

    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
  •   doug    15 年前

    如果我正确理解了您的Q,您需要一个片段,它将在得到答案后立即返回答案,而无需进一步遍历“命令列表”。这应该满足您的要求:

    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
  •   Bear    15 年前

    替换为您最喜欢的字符串比较函数。相当快,切中要害。

    matches = ( x for x in list if x[:len(stringToSearchFor)] == stringToSearchFor )
    print matches[0]
    
        10
  •  0
  •   SpliFF    15 年前
    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