Diese Aufgabe besteht darin, nach der Glob-Erweiterung den kürzesten Pfad zu einer Datei auszugeben.
Was ist Shell Globbing? In den meisten Shells können Sie das *
Zeichen in einem Pfad verwenden, um alle Zeichen an der Position darzustellen. Beispiel: Wenn das Verzeichnis foo
Dateien enthält bar
baz
und asdf
, foo/b*
wird es auf erweitert foo/bar foo/baz
.
Nehmen wir nun an, das aktuelle Verzeichnis enthält eine aufgerufene Datei ihavealongname
und sonst nichts. Wenn ich auf diese Datei verweisen möchte, gebe ich möglicherweise etwas ein *
, das nur diese eine Datei darstellt, anstatt den vollständigen Namen einzugeben.
Wenn das Verzeichnis auch eine Datei namens enthält ialsohavealongname
, kann ich das nicht tun *
, da es mit beiden Dateien übereinstimmt. Das müsste ich zumindest tun , ih*
.
Das *
Muster funktioniert auch für übereinstimmende Verzeichnisse über der gesuchten Datei. Wenn es nur zwei Verzeichnisse foo
und bar
, sondern foo
enthält nur eine Datei baz
und bar
enthält Datei asdf
, kann ich überein foo/baz
mit */baz
. Oder noch prägnanter */b*
. Wenn bar
leer */*
wäre , würde funktionieren.
Ihre Aufgabe: Geben Sie bei einem String-Array von Pfaden, die das "aktuelle Verzeichnis" und einen einzelnen Zielpfad darstellen, den kürzestmöglichen String aus, der nach dem Erweitern von * s nur auf diesen Zielpfad erweitert wird.
Der Zielpfad kann als eigene Zeichenfolge, als Index für das Array von Pfaden, als erstes Element im Array der übergebenen Pfade oder auf eine andere bequeme Weise verwendet werden, die nicht fest codiert ist. Fragen Sie in Kommentaren, wenn Sie sich nicht sicher sind.
Der Zielpfad ist garantiert im "aktuellen Verzeichnis" vorhanden.
Sie können davon ausgehen, dass alle Pfade nur alphanumerische ASCII (und /
s) enthalten. Sie können als Eingabepfade Roots (beginnend mit /
) oder relativ (nicht beginnend mit /
) verwenden.
Wenn es mehrere gleich kurze Möglichkeiten gibt, geben Sie eine oder alle zurück.
Das ist Code-Golf , die wenigsten Bytes gewinnen!
Testfälle dank Kevin Cruijssen .
quelle
*
,?
,[
etc? Es wäre vielleicht am einfachsten, wenn Sie nur*
und Perl ausführenglob
, um alle Dateinamen zu erhalten, die relevant sein können (zBfoo/bar/baz
wird*/*/*
). Danach wird es eine Herausforderung für die Zeichenfolgenverarbeitung. Und diese Herausforderung ist schon schwer genug. Ich denke, diese Herausforderung wäre sauberer, wenn "bei einer Liste alphanumerischer (und/
) relativer Pfade der kürzeste Glob gefunden wird, der nur diesem vorhandenena*f
wählenazzf
ausazzf
,azzg
,bzzf
. Verlängern Sie nach Belieben bisa*b*c
etc ..Antworten:
Perl 5 ,
136107102 BytesBeinhaltet
+2
fürn0
Geben Sie eine Liste der Dateien auf STDIN. Die erste wird als Zieldatei angenommen
Nur der Code, ohne die Zeilenumbrüche wörtlich zu machen:
Abstürze absichtlich nach dem Drucken der Lösung.
Scheint immer noch zu lang (die Verwendung von
$a
und1/0
ist sehr umständlich), aber es ist ein Anfang und sollte einigermaßen effizient sein.Probieren Sie es online aus!
Wie es funktioniert
Das Programm erstellt Kandidaten-Globs, indem es sie von hinten nach vorne wächst, beginnend mit der leeren Zeichenfolge. Er tut dies in einer Breiten Weise so erste Klackse der Länge 0 ist erprobt (nur ``), dann Länge 1 (wie
t
,i
,*
), nächste Länge 2 (wiefb
,i*
,*g
,**
), nächste Länge 3 und so weiter , bis ein Es wurde ein Glob gefunden, der nur dem ersten Pfad entspricht. Dies ist dann der kürzeste Glob, der das Problem löst (andere mit derselben Länge können existieren).Die Globs der Länge
n+1
werden aus den Globs der Länge generiert,n
indem jedes Zeichen aus der Liste der Pfade und auch*
vor jedem Glob der Länge vorangestellt wirdn
. So zB Länge 3 glob*i*
wird dazu beitragen , Länge 4 Klacksef*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
und schließlich**i*
. Beachten Sie, dass jedem Zeichen aus der Liste der Eingabepfade vorangestellt wird, auch wenn es mehrmals vorkommt oder überhaupt keinen Sinn ergibt, da es zu etwas führt, das niemals übereinstimmen kann.Dies naiv zu tun würde zu einer kombinatorischen Explosion führen. Aus diesem Grund wird jeder Kandidaten-Glob dahingehend bewertet, wie nützlich er ist, indem ermittelt wird, an welchen Punkten in den Pfaden er übereinstimmen könnte, wenn der Glob am Ende eines vollständigen Glob verwendet würde. Dazu füge ich
;
an jeder Stelle, an der eine Übereinstimmung möglich ist, ein ein. Zum Beispiel für den Globt*
bekomme ich den String:Dies repräsentiert die "Unterscheidungskraft" des Globus. Jeder Globus, der genau die gleiche Unterscheidungskraft hat, ist gleich gut. Wenn Sie sie am Ende eines vollständigen Globus durch andere ersetzen, stimmen sie alle genau mit denselben Pfaden überein. Sie können also genauso gut die kürzeste verwenden.
n
Wenn ich also die Länge der Globs betrachte, schaue ich zuerst auf ihre Unterscheidungskraft. Wenn es gesehen wurde, bevor es einen anderen Globus mit einer Längen
oder kürzer gab, der bereits berücksichtigt und erweitert wurde, ist dieser Globus sinnlos und wird beschnitten. Dies wird zum Beispiel Kandidaten loswerden,**i*
da die gleiche Unterscheidungskraft bereits als gesehen wurde*i*
. Es beschneidet auch unmögliche Kandidaten wie,f*i*
da die Unterscheidungszeichenfolge keine hat;
und sei einfach die ursprüngliche Liste der Pfade. Nur der allererste unmögliche Glob wird akzeptiert, alle anderen haben die gleiche Unterscheidungskraft und werden beschnitten. Und selbst das erste wird nicht wirklich erweitert, da alle Erweiterungen immer noch unmöglich sind und beschnitten werden, wenn sie berücksichtigt werden. Wird gleichermaßenin*
voni*
etc. beschnitten .Das Obige führt zu einem sehr aggressiven Beschneiden und das Programm ist daher in der Lage, komplexe Fälle in sehr kurzer Zeit zu bearbeiten. Eine große Ineffizienz besteht jedoch darin, dass den Kandidaten-Globs alle möglichen Zeichen vorangestellt werden, nicht nur diejenigen, die sich unmittelbar vor einem
;
Teil der Unterscheidungszeichenfolge im Zielpfad befinden. Alle hinzugefügten Zeichen, die sich nicht vor einem;
befinden, sind kein Problem, da sie zu einem unmöglichen Glob führen, der bei Betrachtung beschnitten wird, die Zeichen jedoch noch kurz zuvor;
auf den anderen Pfaden belassen. Am Ende erstellt das Programm also auch Globs, die mit jeder Kombination der angegebenen Pfade übereinstimmen können. Es hat keine Ahnung, dass es sich auf den ersten Weg konzentrieren sollte.Betrachten Sie nun eine Lösung für das Problem. Im gegebenen Beispiel könnte das sein
*/*er/t
. Dies ergibt die folgende Unterscheidungszeichenfolge:Ich erkenne eine Lösung, indem ich ein
;
an der ersten Position habe (damit es mit dem ersten Pfad übereinstimmt) und kein;
am Anfang eines anderen Pfades (damit die anderen nicht übereinstimmen).Mit dem erklärten Algorithmus komme ich nun zum eigentlichen Programm:
Die Kandidaten-Globs befinden sich in einem Array,
@a
das ich mit einer Variablen durchlaufe ,$a
die den aktuell betrachteten Glob enthält. Anstelle*
im Glob werde ich jedoch verwenden,\w*
so$a
ist eigentlich ein Regex anstelle eines Glob. Ich werde eine Verrücktheit der Perl-for-Schleife missbrauchen, bei der Sie Elemente an das Array anhängen können, das während der Schleife geloopt wird, und diese neuen Elemente in der Schleife aufgenommen werden. Da sich beim Generieren der Längen-n+1
Globs bereits alle Längen-n
Globs im Array befinden, ist@a
dies die Breite zuerst.Aufgrund der
-n0
Option (implizite Schleife über die gesamte Eingabe) wird die Liste der Pfade$_
als eine große Zeichenfolge angezeigt, wobei jeder Pfad mit einer neuen Zeile abgeschlossen wirdIm Inneren
{ }
haben wir:Ups, ich habe es gerade zerstört
$_
und ich werde es für die nächste Schleife brauchen. Wickeln Sie also den eigentlichen Arbeitscode einDies entspricht der leeren Zeichenfolge am Anfang von
$_
und ermöglicht es Ihnen, Code auszuführen, um zu bestimmen, durch was er ersetzt wird. Wenn ich sicher gehe, dass dieser Code als leere Zeichenfolge ausgewertet wird,$_
bleibt er am Ende unverändert, auch wenn ich ihn$_
während änderecode
.Zurück zu kurz nachdem ich durch
$_
die unterscheidende Zeichenfolge ersetzt wurde:Das ist wie:
//
in perl ist'defined or
. Es ist wie ein Kurzschluss,or
bei dem das zweite Argument nur ausgewertet wird, wenn das erste Argument vorliegtundef
. Und es kann wie+=
in einigen anderen Sprachen mit einer Aufgabe kombiniert werden . Also , wenn sie Schlüssel$_
in Hash%seen
istundef
(was ist das, was man bekommt , wenn ein nicht existierendes Element zugreifen) nur dann Ausdruck ausführen und als Wert Schlüssel zuweisen$_
. Wenn ich also sicherexpression
gehe , dass nicht zurückgegeben wirdundef
, bedeutet dies im Grunde "Ausdruck genau dann auswerten, wenn dies das erste Mal ist, dass wir diese bestimmte Unterscheidungszeichenfolge sehen". Und weil$_
garantiert ein enthält\n
, ist es in der Tat sicher, den globalen Perl-Hash zu missbrauchen, um die unterscheidenden Zeichenfolgen zu speichern, also$$_
statt$seen{$_}
Für die
expression
ich benutze:Grundsätzlich "Für jedes Zeichen (außer Zeilenumbruch) in der Unterscheidungszeichenfolge und stellen
*
Sie es auch dem aktuellen Glob voran und verschieben Sie dieses auf das Array der Kandidaten-Globs". Execpt Ich verwende\w*
für*
, um einen gültigen regulären Ausdruck zu erhalten (ich könnte''
anstelle""
eines Backslashs verwenden, aber dann konnte ich meinen Code nicht über die Befehlszeile ausführen). Beachten Sie, dass dies auch die aufnimmt;
und sie zu den Kandidaten-Globs hinzufügt, aber wenn Sie sie später zu den wiederhergestellten testen, die$_
keine haben;
, wird dies wieder ein unmöglicher Glob sein und beschnitten werden.Beachten Sie, dass
/^;/>/\n;/
der Wert der leeren Zeichenfolge entspricht, falls noch keine Lösung gefunden wurde. Dies fungiert also als leere Ersatzzeichenfolge und$_
wird wiederhergestelltquelle
-E
Aktiviert die neueste Sprachstufe. Sie benötigen mindestens Perl,5.10.0
um verwenden zu könnensay
. Alsouse 5.10.0;
in den Header-Bereich setzen und es wird funktionieren. Optionen zum Festlegen der Sprachstufe gelten sowieso als kostenlos, auch wenn Sie dies nicht mit verwenden können-E
. Tatsächlich zählen heutzutage alle Optionen als kostenlos (also muss ich nicht einmal zählenn0
), aber ich halte das für zu nachsichtig für Perl1/
Lösung ist also gültig! Ich muss mich auch daran erinnern ...Java 10,
854824796738728703688655652647624 BytesWas für ein Durcheinander. Dies ist sicherlich keine einfache Herausforderung in Java.
Kann definitiv um ein paar hundert Bytes gespielt werden, aber ich bin nur froh, dass es jetzt endlich funktioniert.Erzählte dir. :)-5 Bytes dank @ceilingcat .
-23 Bytes Umschalten von Java 8 auf Java 10
Eingabe als String-Array von Dateipfaden (mit Verzeichnissen als getrennten Elementen und allen Elementen, die einen führenden enthalten
/
) und als String mit Eingabedateipfad zum Abtasten.Erläuterung:
Probieren Sie es online aus. (Die Testfälle mit
ialsohavealongname
/ihavealongnameaswell
sind leicht in der Länge reduziert unds.add(x.replaceAll("~+","\\*"));
wurden durch ersetzt{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
, um in 5-10 Sekunden an TIO zu arbeiten, anstatt nach mehr als 60 Sekunden eine Zeitüberschreitung zu verursachen.)Zusätzliche allgemeine Erklärung:
Beispiel: Nehmen wir
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
als gegebene Dateipfade undfoo/bar/test
als Eingabedateipfad zum Abtasten.1) Ich
/
teile zunächst die Dateipfadeingabe durch auf und generiere alle Dateifänge dieser getrennten Wörter:2) Ich generiere dann alle Permutationen mit diesen Wörtern in der gleichen Reihenfolge (erneutes Anwenden der
/
dazwischen und vorne):3) Dann durchlaufe ich die Elemente in dieser Liste oben und überprüfe, ob sie nur mit einem einzelnen Dateipfad im Eingabearray der Dateipfade übereinstimmen. (Ich überprüfe dazu zwei Dinge: Ist die Anzahl der Schrägstriche gleich und stimmt sie mit dem regulären Ausdruck überein, durch den jeder
*
ersetzt wird.*
.)Wenn dies der Fall ist: Behalte den (ersten) kürzesten, den wir am Ende zurückgeben.
quelle
>>>
? Ich weiß,>>
ist bitweise Rechtsverschiebung.>>>
genauso wie>>
. Bei negativen Ganzzahlen wird das Paritätsbit jedoch auf 0 geändert (einige Beispiele finden Sie hier im Abschnitt " >> vs >>> " ).-1>>>1
ist nur eine kürzere Variante vonInteger.MAX_VALUE
(und1<<31
wäreInteger.MIN_VALUE
).