展开选项卡(实现expand(1))


10

这次您的任务是实现POSIX expand(1)实用程序的变体,该实用程序将制表符扩展为空格。

您的程序将采用制表规范,然后读取标准输入中的输入,并用适当的空格量替换输入中的制表符以到达下一个制表符。结果应写入标准输出

制表符规格

制表符规范由一个数字或一个逗号分隔的制表符列表组成。在单个数字的情况下,将其重复,就好像它的倍数出现在以逗号分隔的列表中一样(即4充当4,8,12,16,20,...)。逗号分隔列表中的每个条目都是一个正整数,可以选择以前缀+。甲+前缀表示在逗号分隔列表中的先前的值的相对差。列表中的第一个值必须是绝对值(即无前缀)。制表符指定下一个非空格字符的列(在扩展的制表符之后),最左边的列作为数字0。制表符应始终扩展到至少一个空格。

输入输出

您可以自行决定将Tabstop规范用作程序的第一个命令行参数,或者从标准中读取作为第一行输入(由换行符终止)。读取制表符后,将处理和扩展剩余的输入(在前一种情况下为所有输入),直到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

评分是纯粹的;最短的代码胜出。

Answers:


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

在输入的第一行读取tabstop规范。

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

编辑:添加了两行,使上次读取的制表位重复,以便单个数字的制表位规范也可以正常工作

i是用于保存最后一个已分析的Tabstop的临时变量。t是从gets.scan行中解析的Tabstob列表。为了达到良好的效果,我们添加了最后一个已分析的Tabstop的81倍。该while gets循环一直持续,直到没有更多的投入。对于输入的每一行,我们用制表符代替空格,一次只能用一个制表符,因为当添加空格时字符串会移动,并且必须重新计算正确的制表符。


我不太了解Ruby,但是您可以写成x+($1?i:0)较短的$1?x+i:x吗?
Timwi 2014年

@Timwi Nope!Ruby对于三元运算符有点奇怪。通常你需要把一个空间在那里的某个地方,因为冒号(:)也可能标志着一个的开始象征,但是由于符号不能以数字开头,:0是OK没有空间。或者其他的东西。有点奇怪。括号似乎也很重要。
daniero 2014年

对我而言,这种制表符扫描看起来很麻烦。在t<<x+($1?i:0);i=x第一个语句中没有更改x,是吗?我认为您需要将其扭转为i=x+($1?i:0);t<<i
Peter Taylor

1
实际上,您可以通过将前两行替换为来节省16 i=t=[](因为i可以保证第一次不需要)。将制表位解析简化为{t<<i=$2.to_i+($1?i:0)},并l完全消除(i已经拥有该值)。但漂亮的一个上不关心制表位是严格递增的:您节省4个字符,我可以借用它来保存2
彼得·泰勒

@PeterTaylor感谢您的输入!这不是直接的越野车,但肯定有点肿。我发现这样盲目地盯着自己的代码太容易了。
daniero 2014年

1

C,228个字符

这是一个开始的C解决方案。这里仍然有很多高尔夫活动(请查看所有这些,if和,for以及putchar……)。与示例测试用例测试,以及与相同的输入,但是48对选项卡的规范。

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);}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.