-join("$args"-split'\b'|%{(,$(,$_[0]*$n+$_))[!!($n=$($_-1))]})
Provalo online!
Abbattersi
Che casino!
A partire da $args
, che è un array a singolo elemento contenente la stringa RLE, sto forzando una stringa effettiva avvolgendola tra virgolette.
Quindi dividerlo per parola limite ( \b
in regex). Questo mi darà una serie di stringhe, in cui ogni elemento è un numero o i token BF che seguono il numero. Così, nell'esempio, i primi 4 elementi della matrice scissione sono 10
, +]>+>
, 3
, +>
(tutti sono stringa).
Successivamente, lo installo in ForEach-Object
( %
) per gestire ogni elemento .
Il mezzo è un noto golfismo PowerShell, con una svolta; si tratta essenzialmente di un operatore ternario fai-da-te, in cui si crea un array di 2 elementi per indicizzarlo utilizzando l'espressione booleana che si desidera testare, per cui un risultato falso ti dà l'elemento 0 e un risultato vero ti dà l'elemento 1.
In questo caso, in realtà creo un array di elementi singoli con la virgola unaria ,
, perché non voglio l'output nel caso vero.
Per prima cosa diamo un'occhiata all'indicizzatore, anche se viene eseguito in seguito.
L'idea è che $_
(l'elemento corrente) potrebbe essere un numero valido o un'altra stringa. Se è un numero, voglio $n
essere il valore di quel numero meno 1 (come numero, non come stringa). Se non lo è, voglio$n
essere falso.
In genere PowerShell tenta di forzare il valore della mano destra sul tipo del lato sinistro, ma può dipendere dall'operazione. Inoltre, "10"+5
ti darebbe una nuova stringa "105"
, mentre 10+"5"
ti darà un intero ( 15
).
Ma le stringhe non possono essere sottratte, quindi PowerShell può inferire automaticamente il valore numerico con una stringa sul lato sinistro della sottrazione, quindi "10"-5
dà 5
.
Quindi, inizio con $_-1
, che mi darà il numero che desidero quando in $_
realtà è un numero, ma quando non lo è non ottengo nulla. In apparenza, "niente" è falso, ma il problema è che si ferma l'esecuzione di quel compito, quindi $n
manterrà il suo valore precedente; non quello che voglio!
Se lo avvolgo in una sottoespressione, quando fallisce, ottengo il mio valore di falso: $($_-1)
.
A tutto ciò che viene assegnato $n
e poiché tale compito è racchiuso tra parentesi, anche il valore assegnato $n
viene passato alla pipeline.
Dato che lo sto usando nell'indicizzatore e voglio 1
che la conversione abbia avuto successo, uso due not
espressioni booleane !!
per convertire questo valore in booleano. Una conversione numerica di successo finisce come vera, mentre il falso nulla ci dà quel dolce, dolce 0
che consente di restituire l'unico elemento in quel falso array ternario.
Tornando a quell'array, l'elemento è questo: $("$($_[0])"*$n*$_)
$(,$_[0]*$n+$_)
"$($_[0])"
- questo è un modo fastidiosamente lungo di ottenere il primo carattere dell'elemento corrente (diciamo, ottenere +
da +[>+
), ma come una stringa e non come un [char]
oggetto. Ho bisogno che sia una stringa perché posso moltiplicare una stringa per un numero per duplicarla, ma non posso farlo con un carattere.
In realtà sono riuscito a salvare 4 caratteri utilizzando un [char]
array anziché una stringa (utilizzando un'altra virgola unaria ,
), quindi sono stato in grado di rimuovere le virgolette e la sottoespressione aggiuntiva. Io posso moltiplicare una matrice di duplicare i suoi elementi. E poiché l'intero risultato di questa iterazione finisce comunque per essere un array e deve essere modificato -join
, l'utilizzo di un array qui non comporta costi aggiuntivi.
Quindi, moltiplico quell'array di stringhe per $n
, per duplicarlo $n
volte. Ricordiamo che $n
potrebbe essere $null
o potrebbe essere il valore delle cifre precedenti meno uno.
Quindi +$_
aggiunge l'elemento corrente alla fine del primo carattere duplicato di quell'elemento. Ecco perché $n
è meno uno.
In questo modo, 10+[>+
finisce con $n
uguale a 9, quindi facciamo 9 +
e lo aggiungiamo alla +[>+
stringa per ottenere il 10 richiesto, più gli altri singoli elementi lungo per il giro.
L'elemento è racchiuso in una sottoespressione $()
perché quando lo $n
è $null
, l'intera espressione non riesce, quindi la creazione dell'array non riesce, quindi l'indicizzatore non viene mai eseguito, quindi $n
non viene mai assegnato.
Il motivo per cui ho usato questo trucco ternario è a causa di una delle sue peculiarità: a differenza di un vero operatore ternario, le espressioni che definiscono gli elementi fanno vengono valutati indipendentemente dal fatto che siano "selezionati", e il primo per quella materia.
Dal momento che ho bisogno di assegnare e quindi utilizzare $n
su iterazioni separate, questo è utile. Il valore dell'elemento dell'array ternario viene valutato con il $n
valore dell'iterazione precedente , quindi l'indicizzatore si riassegna $n
per l'iterazione corrente.
Quindi i ForEach-Object
loop finiscono per emettere tutto ciò che dovrebbe (un mucchio di errori che ignoriamo), ma come una serie di nuove stringhe.
Quindi l'intera cosa viene racchiusa tra parentesi e quindi preceduta da unario -join
per dare la stringa di output.