Я наконец понял, что вы искали. Проблема интересная, однако, глядя на 2 алгоритма, которые вы обнаружили, кажется, что люди имеют совершенно разные мнения о спецификациях;)
Я думаю, что было бы полезно изложить проблему и требования более четко.
Задача
Мы ищем способ ускорить набор текста, позволяя пользователям вводить только несколько букв ключевого слова, которое они на самом деле намеревались, и предлагать им список для выбора.
- Ожидается, что все буквы ввода будут в ключевом слове
- Ожидается, что буквы во входных данных будут в том же порядке в ключевом слове
- Список возвращаемых ключевых слов должен быть представлен в согласованном (воспроизводимом) порядке
- Алгоритм должен быть без учета регистра
Анализ
Первые два требования можно суммировать примерно так: для ввода axg
мы ищем слова, соответствующие этому регулярному выражению [^a]*a[^x]*x[^g]*g.*
Третье требование намеренно не выполнено. Порядок, в котором слова должны появляться в списке, должен быть согласованным ... однако трудно догадаться, будет ли подход с оценкой лучше алфавитного. Если список слишком длинный, тогда подход с использованием скоринга может быть лучше, однако для короткого списка глазу будет легче найти определенный элемент в списке, отсортированном очевидным образом.
Кроме того, алфавитный порядок имеет преимущество согласованности при наборе текста: т.е. добавление буквы не полностью переупорядочивает список (болезненный для глаз и мозга), оно просто отфильтровывает элементы, которые больше не соответствуют.
Нет точности при обработке символов Юникода, например, à
похож на a
или другой символ в целом? Поскольку я не знаю ни одного языка, который бы в настоящее время использовал такие символы в своих ключевых словах, я пока позволю этому упасть.
Мое решение:
Для любого ввода я бы построил регулярное выражение, выраженное ранее. Он подходит для Python, потому что язык уже имеет регистрозависимое соответствие.
Затем я сопоставил бы мой (отсортированный по алфавиту) список ключевых слов и вывел бы его с такой фильтрацией.
В псевдокоде:
WORDS = ['Bar', 'Foo', 'FooBar', 'Other']
def GetList(input, words = WORDS):
expr = ['[^' + i + ']*' + i for i in input]
return [w for w in words if re.match(expr, w, re.IGNORECASE)]
Я мог бы использовать однострочник, но думал, что это затеняет код;)
Это решение очень хорошо работает для инкрементных ситуаций (например, когда вы подходите как тип пользователя и, следовательно, продолжаете перестраивать), потому что, когда пользователь добавляет символ, вы можете просто перефильтровать результат, который вы только что вычислили. Таким образом:
- Либо символов мало, поэтому сравнение выполняется быстро, а длина списка не имеет большого значения
- Либо есть много символов, и это означает, что мы фильтруем короткий список, поэтому не имеет большого значения, если сопоставление занимает немного больше времени для элемента
Я должен также отметить, что это регулярное выражение не включает обратное отслеживание и, следовательно, является довольно эффективным. Его также можно смоделировать как простой конечный автомат.