Mettre en œuvre la complétion des onglets

31

L'achèvement des tabulations est une fonctionnalité utile qui complète automatiquement les commandes partiellement écrites. Vous allez le mettre en œuvre.

Par exemple, si les commandes disponibles étaient ['apply','apple','apple pie','eat'], elles ase termineraient par appl, car toutes les commandes commençant par acommencent également par appl.

Entrée sortie

Vous devez entrer une chaîne, A et un ensemble de chaînes, B.

Vous devez sortir le préfixe commun le plus long de tous les B commençant par A.

  • Si aucune des options ne commence par A, retournez A
  • Vous pouvez supposer que B n'est pas vide et que toutes les chaînes sont non vides
  • Vous ne pouvez pas supposer que l'une des options commence par A, ni que le préfixe commun sera plus long que A
  • Vous pouvez être sensible à la casse ou insensible à la casse.
  • Vous avez seulement besoin de gérer l'ASCII imprimable
  • Les éléments intégrés qui effectuent explicitement cette tâche sont autorisés

Cas de test:

'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 '

Notez l'espace de fin sur le dernier cas de test

Ceci est un , alors faites vos réponses aussi courtes que possible!

Nathan Merrill
la source
Pourriez-vous ajouter un exemple avec des caractères ASCII imprimables non alphabétiques pour la postérité?
Conor O'Brien
Plus d'exemples avec des caractères non alphabétiques ne pouvaient pas faire de mal. Je viens de supprimer ma réponse car j'ai réalisé qu'elle rompait avec les entrées contenant \​ou '.
Dennis
Je ne sais pas comment représenter 'dans un exemple. Si j'utilise "pour les chaînes, les chaînes sont différentes des autres exemples.
Nathan Merrill
C'est exactement le problème de ma réponse. : P
Dennis

Réponses:

10

JavaScript (ES6), 75 octets

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

Explication: Filtre tous les préfixes correspondants, puis se joint aux nouvelles lignes et correspond à une expression régulière qui trouve le préfixe commun le plus long de toutes les lignes. S'il n'y a pas de préfixe, l'expression régulière renvoie une chaîne vide, auquel cas nous renvoyons simplement la chaîne d'origine.

Neil
la source
Vous pouvez remplacer e.startsWith(s)par e.match("^"+s)pour un octet hors Currying en sauvera un autre
Shaun H
@ShaunH Je ne peux pas utiliser matchavec ASCII imprimable arbitraire.
Neil
Oh juste regex et contrôler les personnages. vous pouvez toujours curry (s,a)=>às=>a=>
Shaun H
7

Gelée , 14 12 octets

ḣJ$€ċÐff\ṪṪȯ

Essayez-le en ligne! ou vérifier tous les cas de test .

Comment ça marche

ḣ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.
Dennis
la source
6

Pyth, 14 13 octets

Merci à @isaacg pour -1 octet

.xe@F/#z._MQz

Un programme qui prend la liste des chaînes, puis la chaîne, sur STDIN et imprime le résultat.

Vérifier tous les cas de test

Comment ça marche

.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
TheBikingViking
la source
1
f}zT=>/#z
isaacg
5

PowerShell v3 +, 112 octets

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

Prend l'entrée en tant que chaîne $aet tableau de chaînes $b. Utilise l' -likeopérateur pour extraire ces éléments à partir desquels $b(insensible à la casse) commence par $a, les transforme explicitement en tableau @(...)(car le résultat peut être une correspondance en tant que scalaire, auquel cas l'indexation échoue plus tard) et stocke ce tableau dans $c.

Cela constitue la ifclause. S'il n'y a rien $c(c'est- à -dire que rien ne commence par $a, donc le tableau est vide), alors sortez $aavec le else. Autrement ...

Nous convertissons le premier élément $cen un chartableau et parcourons chaque élément, en concaténant $iles chaînes avec le précédent et en plaçant les chaînes sur le pipeline via l'encapsulation des parenthèses. Celles-ci sont filtrées à travers |?{...}(la Where-Objectclause) pour vérifier que le .countof $cest -equal aux .countchoses dans $clesquelles se trouve -likela sous-chaîne (c'est-à-dire que la sous-chaîne correspond à tout dans $ c). Puisque nous construisons nos sous-chaînes dans l'ordre le plus court au plus long, nous avons besoin de la dernière [-1]des chaînes résultantes.

Cas de test

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
AdmBorkBork
la source
4

Python 2, 122 octets

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()

Programme complet; prend la chaîne et la liste de stdin exactement comme indiqué dans les exemples, sauf que les entrées doivent être sur des lignes distinctes.

Vérifier tous les cas de test

DLosc
la source
Pourquoi l.pop()au lieu de l[-1]?
Cyoce
@Cyoce Parce que lc'est généralement un setà ce moment-là, ce qui ne permet pas l'indexation (non ordonné). (Heureusement, les ensembles et les listes sont pris en charge pop().)
DLosc
3

Perl, 54 octets

Comprend +2 pour -Xp(peut être combiné avec -e) et +3 pour -i(ne peut pas être combiné)

Donnez le dictionnaire sur STDIN et le mot après l' -ioption, par exemple:

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

Juste le code:

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

Perl, 61 octets

Comprend +2 pour -0p

Exécutez avec le premier mot suivi des mots du dictionnaire sur STDIN:

tabcompletion.pl
a
apply
apple
apple pie
eat
^D

tabcompletion.pl:

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

Python 2, 112 octets

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]
Lynn
la source
2

Haskell, 67 octets

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

La fonction auxiliaire ?trouve le préfixe commun le plus long de deux chaînes en prenant récursivement le premier caractère tant qu'il est le même pour les deux chaînes et que les chaînes ne sont pas vides.

La fonction principale ne %conserve d'abord que les chaînes de la liste qui commencent par celle donnée s, vérifiée par le préfixe commun le plus long avec l' sêtre s. Pour gérer l'absence de compétitions valides, cela ajoute sun résultat vide via max. Ensuite, il trouve le préfixe commun le plus long de ceux-ci en repliant la fonction binaire ?.

Xnor
la source
2

Python 2, 75 octets

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

Merci à @xnor d'avoir suggéré le intégré, initialement utilisé par @BetaDecay dans cette réponse .

À des fins de notation, ÿpeut être remplacé par un octet DEL. Testez-le sur Ideone .

Dennis
la source
1

D, 88 octets

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

Usage:

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

Le code supprime simplement tous les éléments qqui ne commencent pas p, puis calcule la plus grande sous-séquence initiale commune des éléments restants.

Les paramètres du modèle nous permettent d'économiser deux répétitions de stringet une de auto. L'abus d'exception nous permet d'éviter la variable temporaire et le conditionnel qui seraient autrement nécessaires pour gérer le cas où aucun élément de qcommencer par p.

Rayon
la source
1

Python 2, 107 102 octets

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

À des fins de notation, ÿpeut être remplacé par un octet DEL. Testez-le sur Ideone .

Merci à @xnor pour avoir économisé 5 octets!

Dennis
la source
Avec os.path.commonprefix Beta Decay , vous pouvez le faire faire le travail pour vous.
xnor
Wow, cela économise beaucoup d'octets. Êtes-vous sûr de ne pas vouloir publier cela vous-même?
Dennis
Je ne me sentirais pas bien de le poster moi-même car c'est uniquement l'idée de Beta Decay combinée à votre réponse.
xnor
Pour votre solution, il semble un peu plus court d'itérer for c in ...directement et de se terminer avec une erreur après l'impression if len(set(c))>1:print r or s;_.
xnor
Je pense que cela échouerait si x est un tableau singleton.
Dennis
1

PHP, 167 160 157 152 octets

<?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;

Je pourrais économiser 3 octets de plus en attribuant des variables avec preg_grepet preg_quote, mais eh.

panne

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;
Titus
la source
1

PHP, 156 octets

avec beaucoup d'aide de Titus Merci

<?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 octets

32 octets enregistrés par Titus avec 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;

Je sais que la solution Regex de Titus était plus courte jusqu'à ce que Titus m'aide à améliorer mon chemin. Peut-être que la façon dont j'ai trouvé est intéressante pour toi

Jörg Hülsermann
la source
1
1) Remplacez $zpar $spour fixer le apple, [eat,dine]boîtier. 2) $l=est obsolète; Vous n'utilisez pas cette variable. (-2) 3) $i++<$mest plus court que ++$i<=$m. (-1) 4) substr($x,0,$i);est plus court que str_split($x,$i)[0]. (-3) 5) Vous pouvez mettre $r[]=$và l'intérieur du strlen. (-5)
Titus
1
6) <2est plus court que ==1. (-1) 7) Vous pouvez utiliser strstrdans la première boucle: strstr($v,$s)==$v. (-3)
Titus
1
Permettez - moi de reformuler ma question: 5) Vous pouvez combiner $r[]=$v;$m=max($m,strlen($v));à $m=max($m,strlen($r[]=$v));déposer les Curlys. Cela ne touche pas la condition.
Titus
1
Après réflexion, vous n'en avez pas du tout besoin $m. Tout ce dont vous avez besoin est quelque chose qui est> = la longueur minimale des remplacements. Le nouveau 5) Remplacer {$r[]=$v;$m=max($m,strlen($v));}par $r[]=$v;}et <$mavec <strlen($r[0])(-13)
Titus
1
Génial! Et je viens de trouver un autre golf: 9) $r[]=$z=$v;dans la première boucle et {$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;}pour la seconde (-3)
Titus
1

Rétine, 60 octets

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

La nouvelle ligne de fuite est importante. Prend l'entrée en tant que chaîne sur une ligne, puis chaque mot sur une ligne distincte (mais pas de saut de ligne!). Fonctionne de manière similaire à ma réponse JavaScript en faisant correspondre le préfixe commun le plus long de toutes les lignes commençant par la chaîne de la première ligne. S'il n'en trouve pas, il supprime simplement tous les mots.

Neil
la source
0

Scala, 119 octets

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)
}

Explication:

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
corvus_192
la source
0

05AB1E , 14 octets

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

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

ʒ   }           # 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"
Kevin Cruijssen
la source
0

Gaia , 12 octets

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

Essayez-le en ligne!

Prend l'entrée comme B, puis 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
Giuseppe
la source