Schede Espandi (implementa espandi (1))


10

Questa volta il tuo compito è implementare una variante expand(1)dell'utilità POSIX che espande le schede negli spazi.

Il programma deve prendere una specifica tabstop e quindi leggere l'input sullo standard in e sostituire i caratteri di tabulazione nell'input con la quantità appropriata di spazi per raggiungere il tabstop successivo. Il risultato dovrebbe essere scritto allo standard .

Specifiche Tabstop

Una specifica tabstop è costituita da un singolo numero o da un elenco separato da virgole di tabstop. Nel caso di un singolo numero, si ripete come se si verificassero multipli in un elenco separato da virgole (cioè 4agisce come 4,8,12,16,20,...). Ogni voce in un elenco separato da virgole è un numero intero positivo facoltativamente preceduto da a +. Un +prefisso indica una differenza relativa rispetto al valore precedente nell'elenco separato da virgole. Il primo valore nell'elenco deve essere assoluto (ovvero non prefissato). Le schede specificano la colonna del successivo carattere non spaziale (seguendo la scheda espansa), con la colonna più a sinistra considerata come numero 0. Le schede devono sempre espandersi in almeno uno spazio.

Input Output

La specifica tabstop deve essere presa come primo parametro della riga di comando per il programma, oppure letta dallo standard in come prima riga di input (terminata da una nuova riga), a tua discrezione. Dopo che il tabstop è stato letto, l'input rimanente (tutti gli input, nel primo caso) fino a quando EOF deve essere elaborato ed espanso. L'output espanso deve essere scritto nello standard out.

Si presume che tutti i tabstops espansi e tutti gli input abbiano una larghezza massima di 80 colonne. Tutti i tabstops espansi sono in costante aumento.


Esempio

Le specifiche di Tabstop 4,6,+2,+8sono equivalenti 4,6,8,16e con entrambi gli input

ab<Tab>c
<Tab><Tab>d<Tab>e<Tab>f

è espanso in ( indica uno spazio)

ab␣␣c
␣␣␣␣␣␣d␣e␣␣␣␣␣␣␣f

01234567890123456   (Ruler for the above, not part of the output)
          1111111

Il punteggio è puro ; vince il codice più breve.

Risposte:


2

GolfScript ( 77 75 caratteri)

n/(','/{'+'/{~t++}*~:t}%81,{t*}%+:T;{[0\{.9={;T{1$>}?(.)@-' '*}*\)}/;]n+}/;

Sono abbastanza soddisfatto dell'analisi di tabspec.

# Split on commas
','/
# For each element:
{
    # Split on '+'
    '+'/
    # We now have either ["val"] or ["" "val"]
    # The clever bit: fold
    # Folding a block over a one-element array gives that element, so ["val"] => "val"
    # Folding a block over a two-element array puts both elements on the stack and executes,
    # so ["" "val"]{~t++}* evaluates as
    #     "" "val" ~t++
    # which evaluates val, adds the previous value, and concatenates with that empty string
    {~t++}*
    # Either way we now have a string containing one value. Eval it and assign to t
    ~:t
}%

Quindi aggiungo multipli dell'ultimo elemento fino a quando non ho la garanzia di avere abbastanza per raggiungere la fine delle 80 colonne:

81,{t*}%+

Ciò fornisce il comportamento desiderato quando è stato specificato un solo tabstop ed è rilevante solo nei casi in cui le specifiche non menzionano. (NB, la lista delle tab-stop torna a 0 e poi ripete l'ultimo elemento analizzato, ma questo è irrilevante perché quando si tratta di usare la lista cerco il primo elemento maggiore della posizione corrente).

Il resto è piuttosto semplice.


2

Rubino 161 145

Legge la specifica tabstop sulla prima riga di input.

i=t=[]
gets.scan(/(\+)?(\d+)/){t<<i=$2.to_i+($1?i:0)}
81.times{|j|t<<j*i}
while gets
$_.sub!$&," "*(t.find{|s|s>i=$`.size}-i)while~/\t/
print
end

modifica: aggiunte due righe che ripetono l'ultima lettura tabstop in modo che anche le specifiche tabstop di un singolo numero funzionino correttamente

iè una variabile temporanea per contenere l'ultimo tabstop analizzato. tè l'elenco di tabstobs, analizzato dalla gets.scanriga. Per una buona misura aggiungiamo 81 multipli dell'ultimo tabstop analizzato. il while getsciclo continua fino a quando non c'è più input. Per ogni riga di input sostituiamo le schede con gli spazi, una scheda alla volta perché la stringa si sposta mentre aggiungiamo gli spazi e dobbiamo ricalcolare il tabstop corretto.


Non conosco davvero Ruby, ma puoi scrivere x+($1?i:0)come il più corto $1?x+i:x?
Timwi,

@Timwi Nope! Ruby è un po 'strano con l'operatore ternario. Di solito è necessario inserire uno spazio lì da qualche parte, perché i due punti ( :) potrebbero anche segnare l'inizio di un simbolo , ma poiché un simbolo non può iniziare con una cifra, :0va bene senza spazio. O qualcosa. È strano. Anche le parentesi sono cruciali.
daniero,

Quella scansione tabstop mi sembra buggy. Nella t<<x+($1?i:0);i=xprima affermazione non cambia x, vero? Penso che sia necessario invertirlo comei=x+($1?i:0);t<<i
Peter Taylor,

1
In effetti è possibile salvare 16 sostituendo le prime due righe con i=t=[](poiché iè garantito che non sarà necessario la prima volta); semplificando l'analisi tab-stop {t<<i=$2.to_i+($1?i:0)}ed eliminando del ltutto ( icontiene già quel valore). Ma bello non preoccuparsi del fatto che la tabulazione non sia in costante aumento: questo ti fa risparmiare 4 caratteri, e posso prenderlo in prestito per salvare 2.
Peter Taylor,

@PeterTaylor Grazie per l'input! Non era direttamente difettoso, ma sicuramente un po 'gonfio. Trovo troppo facile rimanere ciechi su un codice come questo.
daniero,

1

C, 228 caratteri

Ecco una soluzione C per iniziare le cose. C'è ancora un sacco di golf da fare qui (sguardo a tutte quelle ifs e fors e putchars ...). Testato con l'esempio testcase, nonché con lo stesso input ma 4e 8per le specifiche della scheda.

S[99],i;L,C;main(v){for(v=1;v;)v=scanf("+%d",&C),v=v>0?C+=L:scanf("%d",&C),
v&&(S[L=C]=++i,getchar());for(;i==1&&C<80;)S[C+=L]=1;for(C=L=0;C=~getchar();)
if(C+10)putchar(~C),L+=C+11?1:-L;else for(putchar(32);!S[++L];)putchar(32);}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.