#python #autocomplete
#питон #автозаполнение #python
Вопрос:
Я бы хотел написать код, который выполняет автозаполнение в терминале Linux. Код должен работать следующим образом.
В нем есть список строк (например, «привет», «привет», «как дела», «до свидания», «отлично», …).
В терминале пользователь начнет вводить текст, и когда появится какая-то возможность совпадения, он получит подсказку для возможных строк, из которых он может выбрать (аналогично, как в vim Editor или Google incremental search).
например, он начинает печатать «h», и он получает подсказку
h «привет»
_ «я»
_»ай да ты»
И еще лучше было бы, если бы он завершал слова не только с начала, но и с произвольной части строки.
Комментарии:
1. Каков контекст? Вы запускаете приложение Python в терминале, которое получает входные данные от пользователя? Я не понимаю…
2. @FelixKling Да, именно
Ответ №1:
(Я знаю, что это не совсем то, о чем вы просите, но) Если вы довольны автозаполнением / предложениями, появляющимися на TAB (как используется во многих оболочках), то вы можете быстро начать работу с помощью модуля readline.
Вот краткий пример, основанный на записи PyMOTW Дуга Хеллманна в readline.
import readline
class MyCompleter(object): # Custom completer
def __init__(self, options):
self.options = sorted(options)
def complete(self, text, state):
if state == 0: # on first trigger, build possible matches
if text: # cache matches (entries that start with entered text)
self.matches = [s for s in self.options
if s and s.startswith(text)]
else: # no text entered, all matches possible
self.matches = self.options[:]
# return match indexed by state
try:
return self.matches[state]
except IndexError:
return None
completer = MyCompleter(["hello", "hi", "how are you", "goodbye", "great"])
readline.set_completer(completer.complete)
readline.parse_and_bind('tab: complete')
input = raw_input("Input: ")
print "You entered", input
Это приводит к следующему поведению ( <TAB>
представляющему собой нажатую клавишу tab):
Input: <TAB><TAB>
goodbye great hello hi how are you
Input: h<TAB><TAB>
hello hi how are you
Input: ho<TAB>ow are you
В последней строке (HOTAB введено) есть только одно возможное совпадение, и все предложение «как дела» автоматически заполняется.
Ознакомьтесь со связанными статьями для получения дополнительной информации о readline
.
«И еще лучше было бы , если бы это дополняло слова не только с самого начала … завершение из произвольной части строки.»
Это может быть достигнуто простым изменением критериев соответствия в функции completer, т.е. из:
self.matches = [s for s in self.options
if s and s.startswith(text)]
к чему-то вроде:
self.matches = [s for s in self.options
if text in s]
Это даст вам следующее поведение:
Input: <TAB><TAB>
goodbye great hello hi how are you
Input: o<TAB><TAB>
goodbye hello how are you
Обновления: использование буфера истории (как указано в комментариях)
Простой способ создать псевдо-меню для прокрутки / поиска — это загрузить ключевые слова в буфер истории. Затем вы сможете прокручивать записи с помощью клавиш со стрелками вверх / вниз, а также использовать Ctrl R для выполнения обратного поиска.
Чтобы опробовать это, внесите следующие изменения:
keywords = ["hello", "hi", "how are you", "goodbye", "great"]
completer = MyCompleter(keywords)
readline.set_completer(completer.complete)
readline.parse_and_bind('tab: complete')
for kw in keywords:
readline.add_history(kw)
input = raw_input("Input: ")
print "You entered", input
Когда вы запустите скрипт, попробуйте ввести Ctrl r, за которым следует a. Это вернет первое совпадение, содержащее «a». Введите Ctrl r еще раз для следующего совпадения. Чтобы выбрать запись, нажмите ENTER.
Также попробуйте использовать клавиши ВВЕРХ / ВНИЗ для прокрутки ключевых слов.
Комментарии:
1. Спасибо, я протестировал код. В нем отсутствуют только некоторые функции, которые я хотел бы иметь.
automatic autocomplation while typing, without the need to press tab key
возможность завершить изarbitrary part of the strings
, возможностьchoosing between matches with rows, or other keyboard shortcuts
.2. Я забыл, что эта функция есть в Google, поэтому можно попробовать поискать что-нибудь с помощью Google.
3. AFAIK, нет готового решения для выполнения того, что вы хотите. Такой уровень интерактивности в консольном приложении потребовал бы гораздо больше работы. Как прокомментировал @jro в другом ответе, curses был бы хорошим началом. Я просто указываю на более распространенный подход к автозаполнению на основе командной строки, то есть с использованием readline. Извиняюсь за то, что не смог больше помочь. Удачи с вашим приложением.
4. «Я забыл, что эта функция есть в Google» … да? Какое приложение king of application вы пытаетесь написать?
5. Просто обычное приложение, чтобы сэкономить мне время на ввод. Я надеялся, что есть несколько библиотек, которые могли бы сделать это легко. Ваш ответ приемлем, но я подожду еще некоторое время, если его еще можно улучшить. Спасибо
Ответ №2:
Чтобы включить автозаполнение в оболочке Python, введите это:
import rlcompleter, readline
readline.parse_and_bind('tab:complete')
(благодаря http://blog.e-shell.org/221)
Ответ №3:
Возможно, вы захотите выполнить быструю проверку-автозаполнение:https://github.com/seperman/fast-autocomplete
В нем есть демонстрационный режим, который вы можете вводить и получать результаты по мере ввода:https://zepworks.com/posts/you-autocomplete-me/#part-6-demo
Он очень прост в использовании:
>>> from fast_autocomplete import AutoComplete
>>> words = {'book': {}, 'burrito': {}, 'pizza': {}, 'pasta':{}}
>>> autocomplete = AutoComplete(words=words)
>>> autocomplete.search(word='b', max_cost=3, size=3)
[['book'], ['burrito']]
>>> autocomplete.search(word='bu', max_cost=3, size=3)
[['burrito']]
>>> autocomplete.search(word='barrito', max_cost=3, size=3) # mis-spelling
[['burrito']]
Отказ от ответственности: я написал fast-autocomplete.
Комментарии:
1. На самом деле это очень удобно. Спасибо, сэр!
2. Конечно! Рад слышать, что вы нашли это удобным!
3. Только одно сомнение, масштабируемо ли это. Я имею в виду, если мой словарь достаточно большой, содержащий около миллиона или миллиарда слов, сможет ли он возвращать результаты так быстро?
4. @coderina У меня не было возможности оптимизировать его. Если у кого-то есть время оптимизировать его с помощью Cython, это было бы здорово. Мой вариант использования на момент создания не требовал огромных словарей. Вы можете прочитать больше здесь, внизу: github.com/seperman/fast-autocomplete/issues/10
5. О, точно, я упустил это из виду. Спасибо!
Ответ №4:
Я думаю, вам нужно будет нажать клавишу пользователем.
Вы можете достичь этого (без нажатия enter) с помощью метода, подобного этому:
import termios, os, sys
def getkey():
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
new = termios.tcgetattr(fd)
new[3] = new[3] amp; ~termios.ICANON amp; ~termios.ECHO
new[6][termios.VMIN] = 1
new[6][termios.VTIME] = 0
termios.tcsetattr(fd, termios.TCSANOW, new)
c = None
try:
c = os.read(fd, 1)
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, old)
return c
Затем, если этот ключ является клавишей табуляции (например, это то, что вам нужно реализовать), затем отобразите все возможности для пользователя. Если это любой другой ключ, распечатайте его в стандартном выводе.
О, конечно, вам нужно будет запустить getkey() через некоторое время, пока пользователь нажимает enter. Вы также можете получить метод, подобный raw_input, который будет получать все слова по знакам или отображать все возможности при нажатии на вкладку.
По крайней мере, с этого пункта вы можете начать. Если у вас возникнут какие-либо другие проблемы, не пишите о них.
РЕДАКТИРОВАТЬ 1:
Метод get_word может выглядеть следующим образом:
def get_word():
s = ""
while True:
a = getkey()
if a == "n":
break
elif a == "t":
print "all possibilities"
else:
s = a
return s
word = get_word()
print word
Проблема, с которой я сталкиваюсь прямо сейчас, заключается в способе отображения знака, который вы только что ввели без каких-либо вводов и пробелов, что делает оба print a
и print a,
.
Комментарии:
1. Для отображения предложений вы могли бы затем использовать модуль curses , чтобы иметь возможность имитировать
vi
способ отображения предложений.2. О, не слышал об этом раньше. Выглядит интересно, спасибо 🙂
3. @Gandi спасибо. Не хватает только основной части
incremental matching
иshowing hints while typing
Ответ №5:
Шаги:
-
Создайте файл .pythonrc в домашнем каталоге с помощью этой команды:
vi .pythonrc
-
Введите это содержимое:
import rlcompleter, readline readline.parse_and_bind('tab:complete')
-
Закройте файл
-
А теперь беги
echo "export PYTHONSTARTUP=~/.pythonrc" >> ~/.bashrc
-
Перезапустите терминал
Ответ №6:
Для тех (вроде меня), кто в конечном итоге ищет автозаполнение в интерпретаторе:
Это включает в себя создание файла .pythonrc
, его изменение .bashrc
и import sys
импорт, который необходимо выполнять каждый раз при запуске интерпретатора Python.
Интересно, можно ли автоматизировать последнее для еще большего выигрыша.