10
2
Your task this time is to implement a variant of the POSIX expand(1)
utility which expands tabs to spaces.
Your program is to take a tabstop specification and then read input on standard in and replace tab characters in the input with the appropriate amount of spaces to reach the next tabstop. The result should be written to standard out.
Tabstop specification
A tabstop specification consists of either a single number, or a comma-separated list of tabstops. In the case of a single number, it is repeated as if multiples of it occurred in a comma-separated list (i.e. 4
acts as 4,8,12,16,20,...
). Each entry in a comma-separated list is a positive integer optionally prefixed by a +
. A +
prefix indicates a relative difference to the previous value in the comma-separated list. The first value in the list must be absolute (i.e. unprefixed). The tabstops specify the column of the next non-space character (following the expanded tab), with the leftmost column taken as number 0. Tabs should always expand to at least one space.
Input/output
The tabstop specification is either to be taken as the first command-line parameter to the program, or read from standard in as the first line of input (terminated by a newline), at your discretion. After the tabstop has been read, the remaining input (all input, in the former case) until EOF is to be processed and expanded. The expanded output shall be written to standard out.
All expanded tabstops, and all input, is assumed to be a maximum of 80 columns wide. All expanded tabstops are strictly increasing.
Example
Tabstop specification 4,6,+2,+8
is equivalent to 4,6,8,16
, and with both the input
ab<Tab>c
<Tab><Tab>d<Tab>e<Tab>f
is expanded into (␣
indicates a space)
ab␣␣c
␣␣␣␣␣␣d␣e␣␣␣␣␣␣␣f
01234567890123456 (Ruler for the above, not part of the output)
1111111
Scoring is pure code-golf; shortest code wins.
I don’t really know Ruby, but can you write
x+($1?i:0)
as the shorter$1?x+i:x
? – Timwi – 2014-01-25T00:42:28.483@Timwi Nope! Ruby is a little strange with the ternary operator. Usually you need to put a space in there somewhere, because the colon (
– daniero – 2014-01-25T03:44:21.247:
) could also mark the beginning of a symbol, but since a symbol can't start with a digit,:0
is OK without space. Or something. It's weird. The parentheses are crucial also it seems.That tabstop scanning looks buggy to me. In
t<<x+($1?i:0);i=x
the first statement doesn't changex
, does it? I think you need to reverse it asi=x+($1?i:0);t<<i
– Peter Taylor – 2014-01-25T10:12:32.9831In fact you can save 16 by replacing the first two lines with
i=t=[]
(sincei
is guaranteed not to be needed the first time around); simplifying the tab-stop parse to{t<<i=$2.to_i+($1?i:0)}
, and eliminatingl
entirely (i
already holds that value). But nice one on not caring about the tab stop being strictly increasing: that saves you 4 chars, and I can borrow it to save 2. – Peter Taylor – 2014-01-25T14:06:23.547@PeterTaylor Thanks for the input! It wasn't directly buggy, but certainly a little bloated. I find it too easy to stare oneself blind on code like this. – daniero – 2014-01-25T18:20:16.567
It was directly buggy: given input of
4,6,+2,+8
it produced tab-stops4,6,8,10
rather than4,6,8,16
. – Peter Taylor – 2014-01-25T19:47:26.067@PeterTaylor Wow, I did actually at some point fix exactly that issue; Don't know how it got back in there. Probably during some golfing process. Good catch! – daniero – 2014-01-25T20:30:45.960