-join("$args"-split'\b'|%{(,$(,$_[0]*$n+$_))[!!($n=$($_-1))]})
Probieren Sie es online!
Nervenzusammenbruch
Was für ein Chaos!
Ausgehend von $args
, einem einzelnen Elementarray, das die RLE-Zeichenfolge enthält, erzwinge ich eine tatsächliche Zeichenfolge, indem ich sie in Anführungszeichen setze.
Dann teilen Sie es durch die Wortgrenze ( \b
in Regex). Dadurch erhalte ich eine Reihe von Zeichenfolgen, wobei jedes Element entweder eine Zahl oder die BF-Token ist, die nach der Zahl stehen. So in dem Beispiel sind die ersten 4 Elemente dieser Split - Array 10
, +]>+>
, 3
, +>
(alle sind string).
Als nächstes leite ich das in ForEach-Object
( %
), um mich mit jedem Element zu befassen .
Die Mitte ist ein bekannter PowerShell-Golfismus mit einer Wendung. Es handelt sich im Wesentlichen um einen DIY-Ternäroperator, in dem Sie ein Array mit 2 Elementen erstellen und es dann mit dem zu testenden Booleschen Ausdruck indizieren, wobei ein falsches Ergebnis Element 0 und ein wahres Ergebnis Element 1 ergibt.
In diesem Fall erstelle ich tatsächlich ein einzelnes Elementarray mit dem unären Komma ,
Operator " , da ich keine Ausgabe im wahren Fall möchte.
Schauen wir uns zuerst den Indexer an, auch wenn er später ausgeführt wird.
Die Idee dabei ist, dass $_
(das aktuelle Element) entweder eine gültige Zahl oder eine andere Zeichenfolge sein kann. Wenn es sich um eine Zahl handelt, möchte $n
ich den Wert dieser Zahl minus 1 (als Zahl, nicht als Zeichenfolge) darstellen. Wenn nicht, will ich$n
ich falsch sein.
PowerShell versucht normalerweise, den Wert für die rechte Hand auf den Typ der linken Seite zu setzen, dies kann jedoch vom Vorgang abhängen. "10"+5
Geben Sie zum Hinzufügen eine neue Zeichenfolge ein "105"
, während 10+"5"
Sie eine Ganzzahl ( 15
) erhalten.
Aber Strings kann nicht so statt subtrahiert werden kann Powershell den numerischen Wert automatisch mit einer Schnur auf der linken Seite der Subtraktion schließen, daher "10"-5
gibt5
.
Also, ich beginne mit $_-1
, was mir die Nummer gibt, die ich möchte, wenn $_
es sich tatsächlich um eine Nummer handelt, aber wenn es nicht so ist, bekomme ich nichts. Oberflächlich betrachtet ist "nichts" falsch, aber das Problem ist, dass die Ausführung dieser Zuweisung abgebrochen wird, sodass $n
der vorherige Wert beibehalten wird. nicht was ich will!
Wenn ich es in einen Unterausdruck einbinde, erhalte ich meinen falschen Wert, wenn es fehlschlägt: $($_-1)
.
Das alles wird zugewiesen $n
und da diese Zuweisung selbst in Klammern eingeschlossen ist, der Wert, der zugewiesen wurde$n
auch an die Pipeline übergeben.
Da ich es im Indexer verwende und ich möchte, 1
dass die Konvertierung erfolgreich war, verwende ich zwei boolesche not
Ausdrücke !!
, um diesen Wert in einen booleschen Wert zu konvertieren. Eine erfolgreiche Zahlenumwandlung endet als wahr, während das falsche Nichts uns so süß, süß gibt0
ermöglicht, das einzige Element in diesem gefälschten ternären Array zurückzugeben.
Zurück zu diesem Array lautet das Element wie folgt: $("$($_[0])"*$n*$_)
$(,$_[0]*$n+$_)
"$($_[0])"
- Dies ist ein ärgerlich langer Weg, um das erste Zeichen des aktuellen Elements zu erhalten (sagen wir mal +
von +[>+
), aber als Zeichenfolge und nicht als [char]
Objekt. Ich muss eine Zeichenfolge sein, da ich eine Zeichenfolge mit einer Zahl multiplizieren kann, um sie zu duplizieren, aber ich kann das nicht mit einem Zeichen tun.
Tatsächlich konnte ich 4 Zeichen speichern, indem ich ein [char]
Array anstelle eines Strings verwendete (indem ,
ich ein anderes unäres Komma verwendete ), sodass ich die Anführungszeichen und den zusätzlichen Unterausdruck entfernen konnte. Ich kann ein Array multiplizieren, um seine Elemente zu duplizieren. Und da das gesamte Ergebnis dieser Iteration ohnehin ein Array ist und bearbeitet werden muss -join
, verursacht die Verwendung eines Arrays hier keine zusätzlichen Kosten.
Dann multipliziere ich dieses String- Array mit $n
, um es $n
mal zu duplizieren . Recall , die $n
sein könnte , $null
oder es könnte der Wert der vorstehenden Ziffern minus eins sein.
Dann +$_
addiert das aktuelle Element auf das Ende der duplizierten ersten Zeichen dieses Elements. Deshalb $n
ist minus eins.
Auf diese Weise 10+[>+
endet mit bis $n
gleich 9, dann wir 9 machen +
‚s und die zurück zum hinzufügen+[>+
Zeichenfolge für die Fahrt entlang der erforderlichen 10 sowie die anderen einzelnen Elemente zu erhalten.
Das Element wird in einen Unterausdruck eingeschlossen $()
, weil , wenn $n
ist $null
, der gesamte Ausdruck fehlschlägt, so dass die Anordnung zu schaffen ausfällt, so dass die Weitertaktungs nie ausgeführt wird , so $n
wird nie zugewiesen.
Der Grund , warum ich diesen ternären Trick ist , weil eines seiner Besonderheiten: Im Gegensatz zu einem echten ternären Operator, die Ausdrücke, die die Elemente definieren Sie bekommen ausgewertet , ob sie „ausgewählt“ werden, und das erste was das betrifft.
Da muss ich das zuordnen und dann nutzen $n
separate Iterationen , ist dies hilfreich. Der Wert des ternären Array-Elements wird mit dem Wert der vorherigen Iteration bewertet $n
, und der Indexer weist $n
die aktuelle Iteration neu zu.
Also die ForEach-Object
Schleifen geben also alles aus, was sie sollen (eine Reihe von Fehlern, die wir ignorieren), aber als Array von neuen Zeichenfolgen.
Das Ganze wird also in Klammern eingeschlossen und dann mit unary eingeleitet -join
, um die Ausgabezeichenfolge zu erhalten.