Rozwiń zakładki (zaimplementuj rozwinięcie (1))

10

Twoim zadaniem tym razem jest zaimplementowanie wariantu expand(1)narzędzia POSIX , który rozszerza tabulatory na spacje.

Twój program ma wziąć specyfikację tabstop, a następnie wczytać dane wejściowe w standardzie i zastąpić znaki tabulacji w danych wejściowych odpowiednią ilością spacji, aby przejść do następnego tabstop. Wynik należy zapisać na standardowe wyjście .

Specyfikacja Tabstop

Specyfikacja tabstop składa się z pojedynczej liczby lub listy tabulatorów oddzielonej przecinkami. W przypadku pojedynczej liczby jest ona powtarzana tak, jakby jej wielokrotność wystąpiła na liście oddzielonej przecinkami (tzn. 4Działa jak 4,8,12,16,20,...). Każdy wpis na liście oddzielonej przecinkami jest dodatnią liczbą całkowitą, opcjonalnie poprzedzoną znakiem +. +Przedrostek oznacza względną różnicę w stosunku do poprzedniej wartości w oddzielone przecinkami. Pierwsza wartość na liście musi być bezwzględna (tzn. Bez prefiksu). Tabstopsy określają kolumnę następnego znaku spacji (następującą po rozwiniętej karcie), przy czym kolumna znajdująca się najdalej z lewej strony przyjmuje numer 0. Tabulatory powinny zawsze rozwijać się do co najmniej jednej spacji.

Wejście wyjście

Specyfikację tabstop należy albo przyjąć jako pierwszy parametr programu do wiersza poleceń, albo odczytać ze standardu jako pierwszy wiersz wprowadzania (zakończony nowym wierszem), według własnego uznania. Po odczytaniu tabstopu pozostałe dane wejściowe (wszystkie dane wejściowe, w poprzednim przypadku) do momentu przetworzenia i rozszerzenia EOF. Rozszerzone dane wyjściowe należy zapisać na standardowe wyjście.

Zakłada się, że wszystkie rozwinięte tabstopsy i wszystkie dane wejściowe mają maksymalnie 80 kolumn szerokości. Wszystkie rozszerzone tabstopsy ściśle się zwiększają.


Przykład

Specyfikacja Tabstop 4,6,+2,+8jest równoważna 4,6,8,16z obydwoma danymi wejściowymi

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

jest rozwinięty do ( wskazuje spację)

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

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

Punktacja jest czystym ; najkrótszy kod wygrywa.

Robaczek świętojański
źródło

Odpowiedzi:

2

GolfScript ( 77 75 znaków)

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

Jestem całkiem zadowolony z analizy 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
}%

Następnie dodaję wielokrotności ostatniego elementu, dopóki nie będę mieć wystarczającej ilości, aby dotrzeć do końca 80 kolumn:

81,{t*}%+

Daje to pożądane zachowanie, gdy określono tylko jeden tabstop, a poza tym jest istotne tylko w przypadkach, w których specyfikacja nie wspomina. (Uwaga: powoduje, że lista tabulatorów spada do 0, a następnie powtarza ostatni przeanalizowany element, ale to nie ma znaczenia, ponieważ jeśli chodzi o korzystanie z listy, szukam pierwszego elementu większego niż bieżąca pozycja).

Reszta jest dość prosta.

Peter Taylor
źródło
2

Rubinowy 161 145

Odczytuje specyfikację tabstop w pierwszym wierszu danych wejściowych.

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

edycja: Dodano dwa wiersze, które sprawiają, że ostatni odczyt tabstop jest powtarzany, dzięki czemu specyfikacje tabstop dla pojedynczej liczby również działają poprawnie

ijest zmienną tymczasową do przechowywania ostatniego przeanalizowanego tabstopu. tto lista tabstobs, parsowana z gets.scanlinii. Dla lepszego pomiaru dodajemy 81 wielokrotności ostatniego przeanalizowanego tabstopu. while getspętla leci aż nie ma więcej wejściowego. W każdym wierszu danych wejściowych zastępujemy tabulatory spacjami, po jednej tabulacji, ponieważ ciąg znaków przesuwa się w miarę dodawania spacji i musimy ponownie obliczyć prawidłowy tabulator.

daniero
źródło
Naprawdę nie znam Ruby, ale czy potrafisz pisać x+($1?i:0)jako krótszy $1?x+i:x?
Timwi
@Timwi Nope! Ruby jest trochę dziwna z operatorem trójskładnikowym. Zazwyczaj trzeba gdzieś wstawić spację, ponieważ dwukropek ( :) może również oznaczać początek symbolu , ale ponieważ symbol nie może zaczynać się cyfrą, :0bez spacji jest OK. Lub coś. To dziwne. Wydaje się, że nawiasy są również kluczowe.
daniero
To skanowanie tabstop wydaje mi się błędne. W t<<x+($1?i:0);i=xpierwszym stwierdzeniu się nie zmienia x, prawda? Myślę, że musisz to odwrócić, ponieważi=x+($1?i:0);t<<i
Peter Taylor
1
W rzeczywistości możesz zapisać 16, zastępując pierwsze dwie linie i=t=[](ponieważ igwarantuje się, że nie będzie potrzebny za pierwszym razem); uproszczenie parsowania tabulatorów {t<<i=$2.to_i+($1?i:0)}i lcałkowite wyeliminowanie ( ijuż posiada tę wartość). Ale miło, że nie przejmuję się tym, że karta przestaje się zwiększać: to oszczędza ci 4 znaki i mogę pożyczyć, aby uratować 2.
Peter Taylor
@PeterTaylor Dzięki za wkład! To nie było bezpośrednio błędne, ale na pewno trochę rozdęte. Zbyt łatwo jest mi się ślepo patrzeć na kod w ten sposób.
daniero
1

C, 228 znaków

Oto rozwiązanie C na początek. Jest jeszcze wiele do zrobienia golfa (patrzeć na te wszystkie ifs i fors i putchars ...). Testowane na przykładzie testcase, a także z tego samego wkładu, ale 4i 8w specyfikacji karty.

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);}
Robaczek świętojański
źródło