Реализация вкладки завершения


31

Завершение табуляции - полезная функция, которая автоматически завершает частично написанные команды. Вы собираетесь это реализовать.

Например, если бы доступные команды были ['apply','apple','apple pie','eat'], то aзавершился бы так appl, как все команды, начинающиеся сa также начинаются с appl.

Ввод, вывод

Вам нужно ввести строку A и набор строк B.

Вам нужно вывести самый длинный общий префикс из всех B, который начинается с A.

  • Если ни один из вариантов не начинается с A, верните A
  • Вы можете предположить, что B непусто, и что все строки непусты
  • Вы не можете предполагать, что любой из параметров начинается с A, или что общий префикс будет длиннее, чем A
  • Вы можете быть чувствительными к регистру или без учета регистра.
  • Вам нужно только обрабатывать ASCII для печати
  • Встроенные модули, которые явно выполняют эту задачу, разрешены

Тестовые случаи:

'a'       ['apply','apple','apple pie','eat'] => 'appl'
'a'       ['apple pie']                       => 'apple pie'
'apple'   ['eat','dine']                      => 'apple'
'program' ['programa','programb']             => 'program'
'*%a('    ['*%a()-T>','*%a()-T<','@Da^n&']    => '*%a()-T'
'a'       ['abs','absolute','answer']         => 'a'
'a'       ['a','abs']                         => 'a'
'one to'  ['one to one','one to many']        => 'one to '

Обратите внимание на завершающий пробел в последнем тесте

Это , поэтому делайте ваши ответы как можно короче!



Не могли бы вы добавить пример с не алфавитными печатными символами ASCII для потомков?
Конор О'Брайен,

Больше примеров с неалфавитными символами не могло повредить. Я просто удалил свой ответ, потому что понял, что он не работает с входными данными, содержащими \​или '.
Деннис

Не уверен, как представить 'в примере. Если я использую "для строк, то строки отличаются от других примеров.
Натан Меррилл

Это именно та проблема, в которой был мой ответ. : P
Деннис

Ответы:


10

JavaScript (ES6), 75 байт

(s,a)=>/^(.*).*(\n\1.*)*$/.exec(a.filter(e=>e.startsWith(s)).join`
`)[1]||s

Объяснение: Фильтрует все совпадающие префиксы, затем объединяет их с символами новой строки и сопоставляет с регулярным выражением, которое находит самый длинный общий префикс из всех строк. Если префиксов нет, регулярное выражение возвращает пустую строку, и в этом случае мы просто возвращаем исходную строку.


Вы можете заменить e.startsWith(s)с e.match("^"+s)на один байт от Карринг сохранит другой
Shaun H

@ShaunH Я не могу использовать matchпроизвольную печатную версию ASCII.
Нил

О, правильное регулярное выражение и управляющие символы. Вы все еще можете снискать (s,a)=>кs=>a=>
Shaun H

7

Желе , 14 12 байт

ḣJ$€ċÐff\ṪṪȯ

Попробуйте онлайн! или проверьте все контрольные примеры .

Как это работает

ḣJ$€ċÐff\ṪṪȯ  Main link. Left argument: B. Right argument: A

  $€          Convert the two links to the left into a monadic chain and apply it
              to each string s in B.
 J              Generate the indices of s, i.e., [1, ..., len(s)].
ḣ               Head; for each index i, take the first i characters of s.
              This generates the prefixes of all strings in B.
     Ðf       Filter; keep prefixes for which the link to the left returns 1.
   ċ            Count the number of times A appears in the prefixes of that string.
       f\     Do a cumulative (i.e., keeping all intermediate values) reduce by
              filter, keeping only common prefixes. f/ is a more obvious choice,
              but it errors on an empty array, i.e., when A isn't a prefix of any
              string in B.
         Ṫ    Tail; take the last prefix array (if any) or return 0.
          Ṫ   Tail; take the last common prefix (if any) or return 0.
           ȯ  Logical OR (flat); replace 0 with A, leave strings untouched.

6

Pyth, 14 13 байтов

Спасибо @isaacg за -1 байт

.xe@F/#z._MQz

Программа, которая принимает список строк, а затем строку в STDIN и печатает результат.

Проверьте все контрольные примеры

Как это работает

.xe@F/#z._MQz  Program. Inputs: Q, z
        ._MQ   Map prefixes over Q
     /#z       Filter that by count(z)>0, removing the prefixes corresponding to elements
               in Q that do not start with z
   @F          Fold intersection over that. This yields all the common prefixes
  e            Yield the last element of that, giving the longest common prefix, since the
               prefixes are already sorted by length
.x             But if that throws an exception since no elements of Q start with z:
            z  Yield z instead
               Implicitly print

1
f}zT=>/#z
Исаак

5

PowerShell v3 +, 112 байт

param($a,$b)if($c=@($b-like"$a*")){([char[]]$c[0]|%{($i+="$_")}|?{($c-like"$_*").count-eq$c.count})[-1]}else{$a}

Принимает ввод в виде строки $aи массива строк $b. Использует -likeоператор для извлечения этих элементов из $bэтого (без учета регистра), с которого они $aявно преобразуются в массив @(...)(так как результатом может быть одно совпадение в виде скаляра, в этом случае индексация позднее не выполняется), и сохраняют этот массив в $c.

Это формирует ifпункт. Если в нем ничего нет $c(т. Е. Ничего не начинается с $aмассива, поэтому массив пуст), выведите результат $aс else. Иначе ...

Мы приводим первый элемент $cкак char-array и перебираем каждый элемент, объединяя строки с предыдущим $iи помещая строки в конвейер с помощью инкапсулирующих паренов. Те , фильтруют через |?{...}Where-Objectпункте) , чтобы убедиться в том , что .countв $cэто -eqUAL на .countвещи в $cтом , что есть -likeподстрока (т.е. подстрока соответствует всем в $ с). Поскольку мы строим наши подстроки в порядке от кратчайшего до самого длинного, нам нужна последняя [-1]из результирующих строк.

Тестовые случаи

PS C:\Tools\Scripts\golfing> $tests=@('a',@('apply','apple','apple pie','eat')),@('a',@('apple pie')),@('apple',@('eat','dine')),@('program',@('programa','programb')),@('one to',@('one to one','one to many')),@('*%a(',@('*%a()-T>', '*%a()-T<', '@Da^n&'))

PS C:\Tools\Scripts\golfing> $tests|%{""+$_[0]+" ("+($_[1]-join',')+") -> "+(.\implement-tab-completion.ps1 $_[0] $_[1])}
a (apply,apple,apple pie,eat) -> appl
a (apple pie) -> apple pie
apple (eat,dine) -> apple
program (programa,programb) -> program
one to (one to one,one to many) -> one to 
*%a( (*%a()-T>,*%a()-T<,@Da^n&) -> *%a()-T

4

Python 2, 122 байта

s=input();l=[x for x in input()if x[:len(s)]==s]or[s];i=len(l[0])
while len(l)>1:i-=1;l=set(x[:i]for x in l)
print l.pop()

Полная программа; принимает строку и список из stdin точно так, как указано в примерах, за исключением того, что входные данные должны быть в отдельных строках.

Проверьте все контрольные примеры


Почему l.pop()вместо l[-1]?
Cyoce

@Cyoce Потому что lэто обычно setточка, которая не позволяет индексировать (будучи неупорядоченным). (К счастью, поддерживаются и наборы, и списки pop().)
DLosc

3

Perl, 54 байта

Включает +2 для -Xp(можно комбинировать с -e) и +3 для -i(нельзя комбинировать)

Дайте словарь на STDIN и слово после -iопции, например:

perl -ia -Xpe '/^\Q$^I\E.*?(?{$F[$a{$&}++]=$&})^/}{$_=pop@F||$^I'
apply
apple
apple pie
eat
^D

Просто код:

/^\Q$^I\E.*?(?{$F[$a{$&}++]=$&})^/}{$_=pop@F||$^I

3

Perl 61 байт

Включает +2 для -0p

Запустите с первым словом, за которым следуют словарные слова на STDIN:

tabcompletion.pl
a
apply
apple
apple pie
eat
^D

tabcompletion.pl:

#!/usr/bin/perl -0p
/^(.+)
((?!\1).*
)*(\1.*).*
((?!\1).*
|\3.*
)*$|
/;$_=$3||$`

2

Python 2, 112 байт

lambda n,h:[a.pop()for a in[{s[:-i]for s in h if s.find(n)==0}for i in range(-len(`h`),0)]+[{n}]if len(a)==1][0]

2

Haskell, 67 байт

(a:b)?(c:d)|a==c=a:(b?d)
_?_=""
s%l=foldr1(?)$max[s][x|x<-l,x?s==s]

Вспомогательная функция ?находит самый длинный общий префикс из двух строк, рекурсивно беря первый символ, если он одинаков для обеих строк и строки не пустые.

Основная функция %первая хранит только строки в списке , которые начинаются с заданной один s, проверил самый длинный общий префикс с sтого s. Чтобы справиться с отсутствием действительных соревнований, он добавляет sпустой результат через max. Затем он находит самый длинный общий префикс из них, складывая двоичную функцию ?.


2

Python 2, 75 байт

import os
lambda s,x:os.path.commonprefix([t for t in x if s<=t<s+'ÿ'])or s

Спасибо @xnor за предложение встроенного, первоначально использованного @BetaDecay в этом ответе .

В целях оценки ÿможет быть заменен байтом DEL. Проверьте это на Ideone .


1

D, 88 байт

S f(S)(S p,S[]q){try p=q.filter!(a=>a.startsWith(p)).fold!commonPrefix;catch{}return p;}

Использование:

assert(f("a", ["apply","apple","apple pie","eat"]) ==  "appl");

Код просто удаляет все элементы, qкоторые не начинаются с p, а затем вычисляет наибольшую общую начальную подпоследовательность оставшихся элементов.

Шаблонные параметры сохраняют нам два повторения stringи одно из auto. Неправильное использование исключений позволяет нам избежать временных и условных переменных, которые в противном случае были бы необходимы для обработки случая, когда нет элементов, qначинающихся с p.


1

Python 2, 107 102 байта

s,x=input();r='';q=1
for c in zip(*[t for t in x if s<=t<s+'ÿ']):q/=len(set(c));r+=c[0]*q
print r or s

В целях оценки ÿможет быть заменен байтом DEL. Проверьте это на Ideone .

Спасибо @xnor за сохранение 5 байтов!


С , os.path.commonprefix как бета - распад найден , вы можете это сделать для вас работу.
xnor

Вау, это экономит много байтов. Вы уверены, что не хотите размещать это сами?
Деннис

Я не чувствовал бы себя правильным отправлять это непосредственно, так как это - исключительно идея Бета Декай в сочетании с вашим ответом.
xnor

Для вашего решения это выглядит немного короче, чтобы выполнить итерацию for c in ...напрямую и завершиться с ошибкой после печати, как if len(set(c))>1:print r or s;_.
xnor

Я думаю, что это потерпит неудачу, если х является одноэлементным массивом.
Деннис

1

PHP, 167 160 157 152 байта

<?for($r=preg_grep("$^".preg_quote($s=$_GET[s])."$",$a=$_GET[a]);$r[0]>$s&&preg_grep("$^".preg_quote($t=$s.$r[0][strlen($s)])."$",$a)==$r;)$s=$t;echo$s;

Я мог бы сохранить еще 3 байта, назначив переменные с помощью preg_grepи preg_quote, но да.

сломать

for(
    // find items in $a that start with $s
    $r=preg_grep("$^".preg_quote($s=$_GET[s])."$",$a=$_GET[a]);
    // while the first match is longer than $s
    $r[0]>$s
    // and appending the next character of the first match
    &&preg_grep("$^".preg_quote($t=$s.$r[0][strlen($s)])."$",$a)
    // does not change the matches
    ==$r
;)
    // keep appending
    $s=$t;
return$s;

1

PHP, 156 байт

с большой помощью от Тита Спасибо

<?foreach($_GET[t]as$v)if(strstr($v,$s=$_GET[s])==$v)$r[]=$z=$v;for(;$i++<strlen($z);){$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;}echo$s;

PHP, 199 байт

32 байта спасает Титус с array_unique

<?foreach($_GET[t]as$v)if(strstr($v,$s=$_GET[s])==$v)$r[]=$v;for(;$i++<strlen($r[0]);$a=[]){foreach($r as$x)$a[]=substr($x,0,$i);if(count($r)==count($a)&count(array_unique($a))<2)$s=$a[0];}echo$s;

Я знаю, что решение Regex от Titus было короче, пока Titus не помог мне улучшить мой путь. Может быть, то, как я нашел, вам интересно


1
1) Заменить $zна, $sчтобы исправить apple, [eat,dine]дело. 2) $l=устарел; Вы не используете эту переменную. (-2) 3) $i++<$mкороче чем ++$i<=$m. (-1) 4) substr($x,0,$i);короче str_split($x,$i)[0]. (-3) 5) Вы можете положить $r[]=$vвнутрь strlen. (-5)
Тит

1
6) <2короче чем ==1. (-1) 7) Вы можете использовать strstrв первом цикле: strstr($v,$s)==$v. (-3)
Тит

1
Позвольте мне перефразировать: 5) Вы можете комбинировать , $r[]=$v;$m=max($m,strlen($v));чтобы $m=max($m,strlen($r[]=$v));и падение curlys. Это не касается состояния.
Тит

1
На второй мысли, вам не нужно $mвообще. Все, что вам нужно, это то, что> = минимальная длина замен. Новый 5) Заменить {$r[]=$v;$m=max($m,strlen($v));}на $r[]=$v;}и <$mс <strlen($r[0])(-13)
Титус

1
Большой! И я только что нашел другой гольф: 9) $r[]=$z=$v;в первом цикле и {$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;}во втором (-3)
Титус

1

Сетчатка, 60 байт

^(.*)(\n(?!\1).*)*(\n(\1.*)).*(\n((?!\1)|\4).*)*$
$4
s`\n.*

Трейлинг новой строки является значительным. Принимает ввод как строку в строке, а затем каждое слово в отдельной строке (но не завершающий перевод строки!). Работает аналогично моему ответу JavaScript, сопоставляя самый длинный общий префикс из всех строк, начинающихся со строки в первой строке. Если он не находит его, он просто удаляет все слова.


0

Scala, 119 байт

def f(s:String,a:Seq[Char]*)=a filter(_ startsWith s)reduceOption(_ zip _ takeWhile(t=>t._1==t._2)map(_._1))getOrElse s

Ungolfed:

def tabComplete(input: String, options: Seq[Char]*) = {
  options.
  filter((x: String) => x.startsWith(input)).
  reduceOption((x: Seq[Char], y: Seq[Char]) =>
    x.zip(y).
    takeWhile((t: (Char, Char)) => t._1 == t._2).
    map((t: (Char, Char)) => t._1)
  ).getOrElse(input)
}

Объяснение:

def g(s:String,a:Seq[Char]*)= //define a method g with a string and a vararg array of strings as parameter
  a filter(_ startsWith s)    //filter the options to contains only elements starting with the input
  reduceOption(               //if the filtered array is nonempty, reduce it: 
    _ zip _                     //zip two elements together
    takeWhile(t=>t._1==t._2)    //take the tuples while they contain the same char
    map(_._1)                   //take the first element from each tuple
  )getOrElse s                //else return the input


0

05AB1E , 14 байтов

ʒIÅ?}€ηøʒË}‚˜θ

Попробуйте онлайн или проверьте все тесты .

Объяснение:

ʒ   }           # Filter the (implicit) input-list
 IÅ?            #  Does it start with the (second) input-string
                #   i.e. ["codex","bla","codegolf"] and "c" → ["codex","codegolf"]
     €η         # Then take the prefixes of every remaining string
                #  → [["c","co","cod","code","codex"],
                #     ["c","co","cod","code","codeg","codego","codegol","codegolf"]]
       ø        # Zip/transpose; swapping rows/columns
                #  → [["c","c"],["co","co"],["cod","cod"],["code","code"],["codex","codeg"]]
        ʒ }     # Filter:
         Ë      #  Only keep sublists which only contain the same substrings
                #   → [["c","c"],["co","co"],["cod","cod"],["code","code"]]
               # Pair it with the (second implicit) input
                #  → ["c",["c","c"],["co","co"],["cod","cod"],["code","code"]]
                # (workaround if nothing in the input-list starts with the input-string)
            ˜   # Flatten this list
                #  → ["c","c","c","co","co","cod","cod","code","code"]
             θ  # And only leave the last item (which is output implicitly as result)
                #  → "code"

0

Gaia , 12 байт

e…¦&⊢…Ė⁇_+ₔ)

Попробуйте онлайн!

Принимает ввод как B, а затем A.

e		| eval B as list of strings
 …¦		| take prefixes of each string
   &⊢		| reduce by set intersection
     …		| take list prefixes of each.
      Ė⁇	| Keep only those with A as an element
	_	| flatten
	 +ₔ	| add A to the beginning of the list
	   )	| take the last element
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.