Как написать код для автозаполнения слов и предложений?

#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:

Шаги:

  1. Создайте файл .pythonrc в домашнем каталоге с помощью этой команды: vi .pythonrc

  2. Введите это содержимое:

     import rlcompleter, readline  
    readline.parse_and_bind('tab:complete') 
      
  3. Закройте файл

  4. А теперь беги

    echo "export PYTHONSTARTUP=~/.pythonrc" >> ~/.bashrc

  5. Перезапустите терминал

Ответ №6:

Для тех (вроде меня), кто в конечном итоге ищет автозаполнение в интерпретаторе:

https://web.archive.org/web/20140214003802/http://conjurecode.com/enable-auto-complete-in-python-interpreter/

Это включает в себя создание файла .pythonrc , его изменение .bashrc и import sys импорт, который необходимо выполнять каждый раз при запуске интерпретатора Python.

Интересно, можно ли автоматизировать последнее для еще большего выигрыша.