Развернуть вкладки (внедрить, развернуть (1))

10

Ваша задача на этот раз - реализовать вариант expand(1)утилиты POSIX, который расширяет табуляции до пробелов.

Ваша программа должна взять спецификацию табуляции, а затем прочитать ввод по стандартному вводу и заменить символы табуляции во вводе соответствующим количеством пробелов для перехода к следующей остановке табуляции. Результат должен быть выписан на стандарт .

Табстоп спецификация

Спецификация табуляции состоит либо из одного числа, или разделенного запятыми списка табуляции. В случае одного числа оно повторяется, как если бы его кратные числа встречались в списке через запятую (то есть 4действует как 4,8,12,16,20,...). Каждая запись в списке через запятую представляет собой положительное целое число, необязательно с префиксом a +. +Префикс указывает на относительную разность к предыдущему значению в списке через запятую. Первое значение в списке должно быть абсолютным (то есть без префикса). В закладках указывается столбец следующего непробельного символа (после развернутой вкладки), причем крайний левый столбец принимается за номер 0. Вкладки всегда должны расширяться как минимум до одного пробела.

Ввод, вывод

Спецификация табуляции должна быть либо принята в качестве первого параметра командной строки для программы, либо считана из стандартной в качестве первой строки ввода (завершается символом новой строки), на ваше усмотрение. После прочтения табуляции оставшиеся входные данные (все входные данные в первом случае) до EOF должны быть обработаны и расширены. Расширенный вывод должен быть выписан в стандартный формат.

Предполагается, что все развернутые таб-стопы и весь ввод имеют максимальную ширину 80 столбцов. Все расширенные вкладки строго увеличиваются.


пример

Спецификация Tabstop 4,6,+2,+8эквивалентна 4,6,8,16, и с обоими ввода

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

раскрывается в ( указывает на пробел)

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

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

Подсчет очков - чистый ; самый короткий код выигрывает.

Светляк
источник

Ответы:

2

GolfScript ( 77 75 символов)

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

Я очень доволен разбором 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
}%

Затем я добавляю кратные значения последнего элемента, пока у меня не будет достаточно для достижения конца 80 столбцов:

81,{t*}%+

Это дает желаемое поведение, когда была указана только одна табуляция, и в остальном уместно только в случаях, которые в спецификации не упоминаются. (Обратите внимание, что список табуляций возвращается к 0, а затем повторяется последний проанализированный элемент, но это не имеет значения, потому что когда дело доходит до использования списка, я ищу первый элемент больше текущей позиции).

Все остальное довольно просто.

Питер Тейлор
источник
2

Рубин 161 145

Читает спецификацию табуляции в первой строке ввода.

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

edit: добавлены две строки, которые повторяют последний прочитанный tabstop, чтобы спецификации tabstop одного числа также работали корректно

iэто временная переменная для удержания последней проанализированной табуляции. tсписок таббостов, разобранных со gets.scanстроки Для правильной оценки мы добавляем 81 кратность последней проанализированной табуляции. while getsцикл продолжает идти до тех пор, пока больше нет ввода. Для каждой строки ввода мы заменяем вкладки пробелами, по одной вкладке за раз, потому что строка перемещается по мере добавления пробелов, и мы должны пересчитать правильную остановку табуляции.

daniero
источник
Я действительно не знаю , Руби, но вы можете написать x+($1?i:0)как короче $1?x+i:x?
Тимви
@ Тимви Нет! Руби немного странно с троичным оператором. Обычно вам нужно где-то вставить пробел, потому что двоеточие ( :) может также отмечать начало символа , но, поскольку символ не может начинаться с цифры, :0все в порядке без пробелов. Или что-то. Это странно. Скобки также важны.
Даньеро
Мне кажется, что сканирование на табуляциях глючит. В t<<x+($1?i:0);i=xпервом утверждении не меняется x, не так ли? Я думаю, что вам нужно изменить это какi=x+($1?i:0);t<<i
Питер Тейлор
1
Фактически вы можете сохранить 16, заменив первые две строки на i=t=[](так iкак гарантированно не понадобится в первый раз); упрощение анализа табуляции и полное {t<<i=$2.to_i+($1?i:0)}исключение l( iуже содержит это значение). Но хорошо, если не заботиться о том, чтобы табуляция перестала строго увеличиваться: это экономит вам 4 символа, и я могу одолжить их, чтобы сэкономить 2.
Питер Тейлор
@PeterTaylor Спасибо за вклад! Это не было непосредственно глючит, но, конечно, немного раздутый. Я считаю слишком легким смотреть в глаза на такой код.
Даньеро
1

С, 228 символов

Вот решение C, чтобы начать все с начала. Здесь все еще есть много игры в гольф (посмотрите на все эти ifи другие forи другие putchar...). Протестировано на примере тестового примера, а также с тем же вводом, но 4и 8для спецификации вкладки.

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);}
Светляк
источник