Implementieren Sie die Tab-Vervollständigung

31

Die Tab-Vervollständigung ist eine nützliche Funktion, mit der teilweise geschriebene Befehle automatisch vervollständigt werden. Sie werden es implementieren.

Wenn beispielsweise die verfügbaren Befehle vorhanden wären ['apply','apple','apple pie','eat'], awürde dies abgeschlossen werden appl, da alle Befehle, die mit abeginnen, auch mit beginnen appl.

Input-Output

Sie müssen eine Zeichenfolge A und eine Reihe von Zeichenfolgen B eingeben.

Sie müssen das längste gemeinsame Präfix von B ausgeben, das mit A beginnt.

  • Wenn keine der Optionen mit A beginnt, geben Sie A zurück
  • Sie können davon ausgehen, dass B nicht leer ist und dass alle Zeichenfolgen nicht leer sind
  • Sie können nicht davon ausgehen, dass eine der Optionen mit A beginnt oder dass das gemeinsame Präfix länger als A ist
  • Sie können zwischen Groß- und Kleinschreibung unterscheiden.
  • Sie müssen nur druckbares ASCII verarbeiten
  • Built-Ins, die diese Aufgabe explizit ausführen, sind zulässig

Testfälle:

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

Beachten Sie das Leerzeichen im letzten Testfall

Dies ist ein , also machen Sie Ihre Antworten so kurz wie möglich!

Nathan Merrill
quelle
Related
nimi
Können Sie ein Beispiel mit nicht alphabetischen, druckbaren ASCII-Zeichen für die Nachwelt hinzufügen?
Conor O'Brien
Weitere Beispiele mit nicht alphabetischen Zeichen konnten nicht schaden. Ich habe meine Antwort gerade gelöscht, weil mir aufgefallen ist, dass sie bei Eingaben mit \​oder nicht funktioniert '.
Dennis
Nicht sicher, wie 'in einem Beispiel dargestellt werden soll. Wenn ich "für die Zeichenfolgen verwende, unterscheiden sich die Zeichenfolgen von anderen Beispielen.
Nathan Merrill
Das ist genau das Problem, das meine Antwort hatte. : P
Dennis

Antworten:

10

JavaScript (ES6), 75 Byte

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

Erläuterung: Filtert nach allen übereinstimmenden Präfixen und fügt dann Zeilenumbrüche und Übereinstimmungen mit einem regulären Ausdruck ein, der das längste gemeinsame Präfix aller Zeilen findet. Wenn es keine Präfixe gibt, gibt der reguläre Ausdruck eine leere Zeichenfolge zurück. In diesem Fall geben wir einfach die ursprüngliche Zeichenfolge zurück.

Neil
quelle
Sie können e.startsWith(s)mit e.match("^"+s)für ein Byte aus Curry ersetzen, wird ein anderes speichern
Shaun H
@ShaunH Ich kann nicht matchmit beliebigen druckbaren ASCII- Dateien arbeiten .
Neil
Oh, richtig, Regex und Steuerzeichen. Sie können immer noch (s,a)=>biss=>a=>
Shaun H
7

Jelly , 14 12 Bytes

ḣJ$€ċÐff\ṪṪȯ

Probieren Sie es online! oder überprüfen Sie alle Testfälle .

Wie es funktioniert

ḣ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
quelle
6

Pyth, 14 13 Bytes

Vielen Dank an @isaacg für -1 Byte

.xe@F/#z._MQz

Ein Programm, das die Liste der Zeichenfolgen und anschließend die Zeichenfolge in STDIN aufnimmt und das Ergebnis druckt.

Überprüfen Sie alle Testfälle

Wie es funktioniert

.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
quelle
1
f}zT=>/#z
Isaacg
5

PowerShell v3 +, 112 Byte

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

Übernimmt die Eingabe als Zeichenfolge $aund als Array von Zeichenfolgen $b. Verwendet den -likeOperator, um diese Elemente aus $bdem $aArray @(...)(ohne Berücksichtigung der Groß- / Kleinschreibung) zu ziehen, und wandelt sie explizit in ein Array um (da das Ergebnis eine Übereinstimmung als Skalar sein könnte, in welchem ​​Fall die Indizierung später fehlschlägt) und speichert dieses Array in $c.

Das bildet die ifKlausel. Wenn nichts drin ist $c(dh nichts beginnt mit $a, das Array ist also leer), dann wird $amit ausgegeben else. Andernfalls ...

Wir setzen das erste Element von $cals char-array um und durchlaufen jedes Element, verketten die Zeichenfolgen mit dem vorherigen $iund platzieren die Zeichenfolgen in der Pipeline durch Einkapseln von Parens. Diese wird durch gefiltert |?{...}(die Where-ObjectKlausel) zu überprüfen, ob die .countvon $cist -equal zu den .countDingen in $cdenen sind -likeder Teil (dh entspricht der Teil alles in $ c). Da wir unsere Teilzeichenfolgen in der Reihenfolge von der kürzesten zur längsten erstellen, benötigen wir die letzte [-1]der resultierenden Zeichenfolgen.

Testfälle

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
quelle
4

Python 2, 122 Bytes

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

Volles Programm; Nimmt String und Liste genau wie in den Beispielen angegeben von stdin, mit der Ausnahme, dass die Eingaben in separaten Zeilen erfolgen müssen.

Überprüfen Sie alle Testfälle

DLosc
quelle
Warum l.pop()statt l[-1]?
Cyoce
@Cyoce Da list in der Regel ein setan diesem Punkt, die Indizierung nicht zulässt (ungeordnet). (Zum Glück werden sowohl Sets als auch Listen unterstützt pop().)
DLosc
3

Perl, 54 Bytes

Beinhaltet +2 für -Xp(kann kombiniert werden -e) und +3 für -i(kann nicht kombiniert werden)

Gib das Wörterbuch auf STDIN und das Wort nach der -iOption an, zB:

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

Nur der Code:

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

Perl, 61 Bytes

Beinhaltet +2 für -0p

Führen Sie mit dem ersten Wort gefolgt von den Wörterbuchwörtern auf STDIN aus:

tabcompletion.pl
a
apply
apple
apple pie
eat
^D

tabcompletion.pl:

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

Python 2, 112 Bytes

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
quelle
2

Haskell, 67 Bytes

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

Die Hilfsfunktion ermittelt ?das längste gemeinsame Präfix von zwei Zeichenfolgen, indem sie das erste Zeichen rekursiv verwendet, sofern es für beide Zeichenfolgen gleich ist und die Zeichenfolgen nicht leer sind.

Die Hauptfunktion %behält zunächst nur die Zeichenfolgen in der Liste bei, die mit der angegebenen beginnen s, die durch das längste gemeinsame Präfix mit sSein markiert ist s. Um zu verhindern, dass gültige Wettbewerbe stattfinden, wird sein leeres Ergebnis über hinzugefügt max. Dann findet es das längste gemeinsame Präfix von diesen durch Falten der Binärfunktion ?.

xnor
quelle
2

Python 2, 75 Bytes

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

Vielen Dank an @xnor für den Vorschlag des eingebauten, ursprünglich von @BetaDecay in dieser Antwort verwendeten .

ÿKann zu Bewertungszwecken durch ein DEL-Byte ersetzt werden. Teste es auf Ideone .

Dennis
quelle
1

D 88 Bytes

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

Verwendung:

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

Der Code entfernt einfach alle Elemente q, die nicht mit beginnen p, und berechnet dann die größte gemeinsame Anfangssubsequenz der verbleibenden Elemente.

Die angegebenen Parameter ersparen uns zwei Wiederholungen von stringund eine von auto. Durch den Ausnahmefehler können wir die temporäre Variable und die Bedingung vermeiden, die ansonsten erforderlich wären, um den Fall zu behandeln, bei dem keine Elemente qanfangen p.

Strahl
quelle
1

Python 2, 107 102 Bytes

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

ÿKann zu Bewertungszwecken durch ein DEL-Byte ersetzt werden. Teste es auf Ideone .

Vielen Dank an @xnor für das Speichern von 5 Bytes!

Dennis
quelle
Mit os.path.commonprefix Beta Decay können Sie die Arbeit für sich erledigen lassen.
Xnor
Wow, das spart eine Menge Bytes. Bist du sicher, dass du das nicht selbst posten möchtest?
Dennis
Ich würde es nicht als richtig empfinden, es selbst zu posten, da es nur die Idee von Beta Decay in Verbindung mit Ihrer Antwort ist.
Xnor
Für Ihre Lösung sieht es etwas kürzer aus, for c in ...direkt zu iterieren und mit Fehler nach dem Drucken zu beenden if len(set(c))>1:print r or s;_.
Xnor
Ich denke, das würde scheitern, wenn x ein Singleton-Array ist.
Dennis
1

PHP, 167 160 157 152 Bytes

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

Ich könnte 3 weitere Bytes sparen, indem ich Variablen mit preg_grepund preg_quotezuordne, aber eh.

Nervenzusammenbruch

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
quelle
1

PHP, 156 Bytes

mit viel hilfe von titus danke

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

32 Bytes spart Titus mit 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;

Ich weiß, dass die Regex-Lösung von Titus kürzer war, bis Titus mir half, meinen Weg zu verbessern. Vielleicht ist der Weg, den ich gefunden habe, interessant für dich

Jörg Hülsermann
quelle
1
1) Ersetzen Sie $zdurch $s, um das apple, [eat,dine]Gehäuse zu reparieren . 2) $l=veraltet ist; Sie verwenden diese Variable nicht. (-2) 3) $i++<$mist kürzer als ++$i<=$m. (-1) 4) substr($x,0,$i);ist kürzer als str_split($x,$i)[0]. (-3) 5) Sie können $r[]=$vinnerhalb des strlen setzen. (-5)
Titus
1
6) <2ist kürzer als ==1. (-1) 7) Sie verwenden könnten strstrin der ersten Schleife: strstr($v,$s)==$v. (-3)
Titus
1
Lassen Sie mich anders formulieren es: 5) Sie kombinieren können $r[]=$v;$m=max($m,strlen($v));zu $m=max($m,strlen($r[]=$v));und die curlys fallen. Dies berührt den Zustand nicht.
Titus
1
Beim zweiten Gedanken brauchst du $müberhaupt nicht. Alles, was Sie brauchen, ist etwas, das> = die Mindestlänge der Ersetzungen ist. Die neuen 5) Ersetzen Sie {$r[]=$v;$m=max($m,strlen($v));}mit $r[]=$v;}und <$mmit <strlen($r[0])(-13)
Titus
1
Groß! Und ich habe gerade einen weiteren Golf gefunden: 9) $r[]=$z=$v;in der ersten Runde und {$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;}für die zweite (-3)
Titus
1

Netzhaut, 60 Bytes

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

Die nachfolgende neue Zeile ist signifikant. Übernimmt die Eingabe als Zeichenfolge in einer Zeile und dann jedes Wort in einer separaten Zeile (aber keine abschließenden Zeilenumbrüche!). Funktioniert ähnlich wie meine JavaScript-Antwort, indem das längste gemeinsame Präfix aller Zeilen abgeglichen wird, die mit der Zeichenfolge in der ersten Zeile beginnen. Wenn es keine findet, werden einfach alle Wörter gelöscht.

Neil
quelle
0

Scala, 119 Bytes

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

Erläuterung:

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
quelle
0

05AB1E , 14 Bytes

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

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung:

ʒ   }           # 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
quelle
0

Gaia , 12 Bytes

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

Probieren Sie es online!

Nimmt die Eingabe als B, dann als 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
quelle