Весьма полезный рецепт, который облегчает общение с коммандной строкой описан здесь, однако попробовать его вживую не удалось, т.к. под мою систему (OpenIndiana) не существует компиляторя языка Go. Так возникла идея переписать указанную программу на более универсальный язык, который точно существует на любой платформе — Perl.
На получившемся примере кода хотел бы продемонстрировать, как при помощи пары строк с использованием регулярных выражений, можно выполнить быстрый и эффективный поиск.
Реализация
Для начала преобразуем переданные функции подсказки в часть будущего регулярного выражения:
$hints =~ s/(.)/$1.*?/g;
Здесь $hints — строка, склеенная из всех подсказок, например, 'abcd'.
Выражение для поиска (.) — это одиночный символ (каждый, учитывая параметр поиска 'g'), заменяем его на себя же ($1 — значение из первых скобок выражения поиска) и дописываем необходимые нам части, а именно:
После каждого символа добавляем блок: '.*?', что означает: любой символ, ноль или более раз, и маркер, который делает модификатор «не жадным» (об этом чуть ниже).
Итого на выходе получаем строку: 'a.*?b.*?c.*?d.*?'
Переходим к основной части, которая осуществляет сравнение строки из «знакомых» папок с подсказкой, условие:
if ($path =~ /^(.*)($hints)$/)
Здесь символ '^' — это «якорь» начала строки, выражение в первых скобках '(.*)' — префикс строки, а вслед за этим выражением — наш подготовленный заранее regexp, содержащий подсказки для поиска, заканчивается выражение вторым «якорем» — '$', который означает совпадение с концом строки.
Поскольку все модификаторы '*' в строке кроме первого, содержат маркеры '?', единственный модификатор без этого маркера становится «жадным», т.е. старается отобрать себе как можно большую часть строки.
В нашем примере, имеем на выходе преобразованную строку: /^(.*)(a.*?b.*?c.*?d.*?)$/
Фактически, поиск в этом случае осуществляется справа налево, т.е. сначала от конца строки ищем ближайший символ 'd', потом слева от него — ближайший символ 'c', затем — ближайший к нему слева символ 'b' и затем — ближайший к нему вимвол 'a', все что будет слева от найденного смвола 'a' попадет в «жадный» префикс. Положение найденного результата в строке мы определим по длине этого префикса, а именно строкой $w = length($1);
(здесь $1 получит значение из первых скобок предыдущего regexp), остальные условия (чем правее, чем лучше) за нас уже выполнил сам regexp.
Остается только дописать функции LoadPaths и add и добисать обработку параметров запуска.
Полный текст скрипта:
hg clone bitbucket.org/eugenet/perlre
Автор: eugene_t