如何实现Python命令行自动补全,但不仅限于字符串开头

7 投票
1 回答
8281 浏览
提问于 2025-04-11 09:28

Python通过它的readline绑定,可以实现很棒的命令行自动补全功能(详细内容可以在这里找到)。

不过,这种补全功能似乎只在字符串的开头有效。如果你想在字符串的中间或结尾进行匹配,readline就不管用了。

我想在一个命令行的Python程序中实现字符串的自动补全,方法是将我输入的内容与一个可用字符串的列表进行匹配。

  • 我想要的自动补全类型可以参考GMail的“收件人”字段。当你输入某个联系人的姓氏时,它会像输入名字一样显示出来。
  • 可能需要使用上下箭头或其他方法来选择匹配的字符串(在readline的情况下可能不需要),这对我来说没问题。
  • 我具体的使用场景是一个命令行程序,用于发送电子邮件。
  • 提供一些具体的代码示例会非常有帮助。

使用像curses这样的终端模拟器也可以。这个程序只需要在Linux上运行,不需要在Mac或Windows上运行。

举个例子:假设我有以下三个字符串在一个列表中

['Paul Eden <paul@domain.com>', 
'Eden Jones <ejones@domain.com>', 
'Somebody Else <somebody@domain.com>']

我希望有一些代码可以在我输入'Eden'后自动补全列表中的前两个项目,然后让我选择其中一个(全部通过命令行和键盘操作)。

1 个回答

10

我不太明白这个问题。你可以使用readline.clear_history和readline.add_history来设置你想要的可补全字符串,然后按控制键加r(control-r)可以在历史记录中向后搜索(就像你在命令行提示符下那样)。例如:

#!/usr/bin/env python

import readline

readline.clear_history()
readline.add_history('foo')
readline.add_history('bar')

while 1:
    print raw_input('> ')

另外,你也可以自己写一个补全器,并把合适的按键绑定到它上面。这个版本使用了缓存,以防你的匹配列表非常大:

#!/usr/bin/env python

import readline

values = ['Paul Eden <paul@domain.com>', 
          'Eden Jones <ejones@domain.com>', 
          'Somebody Else <somebody@domain.com>']
completions = {}

def completer(text, state):
    try:
        matches = completions[text]
    except KeyError:
        matches = [value for value in values
                   if text.upper() in value.upper()]
        completions[text] = matches
    try:
        return matches[state]
    except IndexError:
        return None

readline.set_completer(completer)
readline.parse_and_bind('tab: menu-complete')

while 1:
    a = raw_input('> ')
    print 'said:', a

撰写回答