# Implement a whitespace golfer

Some two-dimensional esolangs, such as Forked, and some non-esolangs, such as Python, can sometimes require spaces before lines of code. This isn't very golfy. Also, I'm lazy and writing a 2d lang that needs lots of spaces before code. Your task is to write a tool that makes these languages golfier.

Of course, this will not be perfect; it cannot be used, for instance, when a number is the first character on a line of source. However, it will generally be useful.

# Challenge

You will write a program or function that either...

• ...takes one argument, a filename or a string, or...

Your program will act like cat, except:

• If the first character on any line is a number, your code will print x spaces, where x is that number.
• Otherwise, it will simply be printed.
• As will every other character in the input.

# Test cases

Input:

foo bar foo bar
1foo bar foo bar foo bar
2foo bar foo bar foo bar foo bar


Output:

foo bar foo bar
foo bar foo bar foo bar
foo bar foo bar foo bar foo bar


Input:

--------v
8|
8|
80
8,
7&


Output:

--------v
|
|
0
,
&


Input:

foo bar
bar foo
foo bar


Output:

foo bar
bar foo
foo bar


Input:

0123456789
1234567890
2345678901
3456789012
4567890123


Output:

123456789
234567890
345678901
456789012
567890123


# Rules

• Output must be exactly as input, except for lines where the first character is a number.
• Your program cannot append/prepend anything to the file, except one trailing newline if you desire.
• Your program may make no assumptions about the input. It may contain empty lines, no numbers, Unicode characters, whatever.
• If a number with more than one digit starts a line (e.g. 523abcdefg), only the first digit (in the example, 5) should turn into spaces.

# Winner

Shortest code in each language wins. Have fun and good luck!

• Sandboxed post – MD XF Aug 8 '17 at 0:01
• Of course, this will not be perfect; it cannot be used, for instance, when a number is the first character on a line of source. Not true, just make the first character a 0 (ahem, your last test case) – HyperNeutrino Aug 8 '17 at 0:16
• Can we read a list of strings from stdin (is this valid)? – Riley Aug 8 '17 at 19:16

# Retina, 9 bytes

m^\d
$*  Try it online! Note: Trailing space on last line. # Cubically, 69 bytes R1B1R3B1~(+50<7?6{+54>7?6{-002+7~?6{(@5*1-1/1)6}}}(-6>7?6&@7+70-4~)6)  Try it online! ## Explanation: First we do this initialization: R1B1R3B1  To set up this cube:  533 004 000 411223455441 311222331440 311222331440 555 555 200  The most important thing about this cube is that face 5 sums to 32, which is the value required to print spaces. Coincidentally, it also happens to be fairly short for all other computation. After that is done: ~( . . . ) Takes the first input, then loops indefinitely +50<7?6{+54>7?6{-002+7~?6{(@5*1-1/1)6}}} Handle leading digit: +50<7?6{ } If input is greater than 47 ('0' is 48) +54>7?6{ } And input is less than 58 ('9' is 57) Then input is a digit -002+7 Set notepad equal to value of input digit ~ Take next input (only convenient place for it) ?6{ } If the notepad isn't 0 ( )6 While the notepad isn't 0: @5 Print a space *1-1/1 Decrement the notepad by one Leading digit handled (-6>7?6&@7+70-4~)6 Handle rest of line: ( )6 While the notepad isn't 0: -6>7?6& Exit if End of Input @7 Print the next character +70-4 Set notepad to 0 if it was a newline ~ Take the next character  • Wow, that's a good use of nested ... everything. +1 – MD XF Aug 8 '17 at 3:52 # Husk, 15 13 bytes -2 bytes thanks to @Zgarb mΓo+?oR' i;±¶  Try it online! Uses the same technique as @Jonathan Allan ### Explanation  ¶ -- split input into a list of lines m -- apply the following function to each line Γ -- deconstruct the string into a head and a tail o+ -- prepend to the tail of the string ... ? ± -- if the head is a digit (n) oR' i -- the string of n spaces -- else ; -- the head of the string -- implicitly print list of strings line-by-line  • 13 bytes with the use of Γ. – Zgarb Aug 8 '17 at 6:39 # JavaScript (ES8), 38 37 bytes a=>a.replace(/^\d/gm,a=>''.padEnd(a))  I don't think it can be improved much more. Saved 1 byte thanks to Shaggy - Use ES8 features. • "I don't think it can be improved much more." - You could save a byte by using ES8's padEnd like so: s=>s.replace(/^\d/gm,m=>"".padEnd(m)) – Shaggy Aug 8 '17 at 10:52 • @Shaggy. I didn't know ES8 is allowed already. Thanks. – user72349 Aug 8 '17 at 15:31 • If there's any single interpreter (i.e.,browser) out there that supports a feature then that feature is fair game here :) – Shaggy Aug 8 '17 at 15:32 # Python 2, 987467 65 bytes -24 bytes thanks to Jonathan Allan. -7 bytes thanks to Mr. Xcoder. for i in open('f'):print' '*int(i[0])+i[1:]if'/'<i[:1]<':'else i,  Try it online! Takes input in the file named f. • Also errors when no digit in the first character of a line (when using a list as a way to choose items all the elements are evaluated) – Jonathan Allan Aug 8 '17 at 1:24 • back to 89 – Jonathan Allan Aug 8 '17 at 1:28 • 87 bytes - TIO link's header is mocking open; code is expecting a file named 'f'. I think it's OK? – Jonathan Allan Aug 8 '17 at 1:38 • Ah, true the ' '*0 is falsey. Using [:1] is still a save though. No need for read I believe (and it would be readlines) since the default behaviour of open is to iterate through the lines. Also there is no need for the mode since 'r' is the default. If I'm right that's 73 ! – Jonathan Allan Aug 8 '17 at 1:57 • – Jonathan Allan Aug 8 '17 at 1:59 # Ruby, 24 21+1 = 25 22 bytes Uses the -p flag. -3 bytes from GB. sub(/^\d/){"%#$&s"%p}


Try it online!

• {"%#$&s"%""} saves 1 byte – G B Aug 8 '17 at 11:06 • And another byte if you use sub instead of gsub – G B Aug 8 '17 at 11:09 • @GB and another byte by putting %p at the end instead of %"". Thanks for your help! – Value Ink Aug 8 '17 at 17:10 # 05AB1E, 10 bytes v0y¬dićú},  Try it online! • How does one input with empty lines? – Jonathan Allan Aug 8 '17 at 0:39 • No idea lol... I'll look into it – Oliver Ni Aug 8 '17 at 7:10 • |vy¬dićú}, works for 10 bytes. – Riley Aug 8 '17 at 13:45 • OK, it's not one cannot input an empty line, it's that the code does not work for an empty line: if one uses a single zero it works, so it must be something about the head not existing (same goes for @Riley's suggested 10 byter by the way). – Jonathan Allan Aug 8 '17 at 15:48 • @JonathanAllan It has something to do with the way | works. It is supposed to push the rest of input as an array with strings, but it stops at empty lines (TIO). I brought this up in the 05AB1E chatroom if you want to know more. – Riley Aug 8 '17 at 17:02 # Python 3, 95 bytes lambda y:'\n'.join(re.sub('^\d',lambda x:' '*int(x.group()),z)for z in y.split('\n')) import re  Try it online! -4 bytes by stealing the regex idea from ThePirateBay • You stole from ThePirateBay, how the tables have turned – joH1 Aug 8 '17 at 10:19 • @Moonstroke HAH lol I didn't even notice that :P – HyperNeutrino Aug 8 '17 at 13:48 # Jelly, 19 bytes V⁶ẋ ḢÇ¹e?ØD; ỴÇ€Yḟ0  A monadic link taking and returning lists of characters, or a full program printing the result. Try it online! ### How? V⁶ẋ - Link 1, make spaces: character (a digit) V - evaluate as Jelly code (get the number the character represents) ⁶ - a space character ẋ - repeat ḢÇ¹e?ØD; - Link 2, process a line: list of characters Ḣ - head (get the first character and modify the line) - Note: yields zero for empty lines ØD - digit characters = "0123456789" ? - if: e - ...condition: exists in? (is the head a digit?) Ç - ...then: call the last link as a monad (with the head as an argument) ¹ - ...else: identity (do nothing; yields the head) ; - concatenate with the beheaded line ỴÇ€Yḟ0 - Main link: list of characters Ỵ - split at newlines Ç€ - call the last link (1) as a monad for €ach Y - join with newlines ḟ0 - filter out any zeros (the results of empty lines)  • beheaded line Is that the actual term? xD – HyperNeutrino Aug 8 '17 at 1:06 • Well, it is now :) – Jonathan Allan Aug 8 '17 at 1:07 • Ahahaha I tried outgolfing you and ended up with a solution essentially identical to yours xD – HyperNeutrino Aug 8 '17 at 1:23 # Perl 5, 13 + 1 (-p) = 14 bytes s/^\d/$"x$&/e  Try it online! # Haskell, 63 bytes unlines.map g.lines g(x:r)|x<';',x>'/'=(' '<$['1'..x])++r
g s=s


Try it online! The first line is an anonymous function which splits a given string into lines, applies the function g to each line and joins the resulting lines with newlines. In g it is checked whether the first character x of a line is a digit. If this is the case, then ['1'..x] yields a string with length equal to the value of the digit x and ' '<$ converts the string into as many spaces. Finally the rest of the line r is appended. If x is not a digit we are in the second equation g s=s and return the line unmodified. # Python 2, 76 72 68 bytes -4 bytes thanks to @ovs! @DeadPossum suggested switching to Python 2, which saved 4 bytes too. Just thought it's nice to have a competitive full program in Python 2 that does not explicitly check if the first character is a digit. This reads the input from a file, f. for i in open('f'): try:r=int(i[0])*" "+i[1:] except:r=i print r,  Try it online! (courtesy of @ovs) • @ovs Thanks for that – Mr. Xcoder Aug 8 '17 at 7:08 • @ovs What did you change (I will do it by hand) ? It tells me that the permalink cannot be decoded – Mr. Xcoder Aug 8 '17 at 7:14 • Instead of printing in every iteration I assigned the output to a variable and printed it all at the end. – ovs Aug 8 '17 at 7:46 • @ovs I managed to get 72 bytes by printing every iteration, thanks for the variable idea! – Mr. Xcoder Aug 8 '17 at 7:52 • Python 2 version of print will give you 68 bytes – Dead Possum Aug 8 '17 at 10:54 # Java 8, 1059997 93 bytes Saved few more bytes thanks to Nevay's suggestion, s->{int i=s.charAt(0);if(i>47&i<58)s=s.substring(1);while(i-->48)s=" "+s;System.out.print(s);}  • You have two bugs in your golfed version: The digit check has to use and instead of or; The brackets after the digit check are missing. Besides that you can save a few bytes by using s->{int i=s.charAt(0);if(i>47&i<58)for(s=s.substring(1);i-->48;s=" "+s);System.out.print(s);} (93 bytes). – Nevay Aug 8 '17 at 12:22 • @Nevay You are right. Thanks. I'll update my answer. – CoderCroc Aug 8 '17 at 12:26 # R, 138 128 bytes -9 bytes thanks to CriminallyVulgar n=readLines();for(d in grep("^[0-9]",n))n[d]=gsub('^.?',paste0(rep(' ',eval(substr(n[d],1,1))),collapse=''),n[d]);cat(n,sep=' ')  This is pretty bad, but it's a bit better now... R is, once again, terrible at strings. Try it online! • I am commenting on behalf of CriminallyVulgar, who suggests a 129-byte version, but does not have enough reputation to comment. – Mr. Xcoder Aug 9 '17 at 10:24 • @Mr.Xcoder Thank you and @CriminallyVulgar! – Giuseppe Aug 9 '17 at 12:49 • 123 Bytes Apparently rep can take a string of an int for the second argument??? – CriminallyVulgar Aug 10 '17 at 8:23 • @CriminallyVulgar huh. it's right there in the docs for rep, now that I check them again: "other inputs being coerced to an integer or double vector". – Giuseppe Aug 10 '17 at 10:26 # Japt (v2.0a0), 11 10 bytes Japt beating Jelly and 05AB1E? That doesn't seem right! r/^\d/m_°ç  Test it ## Explanation Implicit input of string U r/^\d/m  Use Regex replace (r) all occurrences of a digit at the beginning of a line (m is the multiline flag - the g flag is enabled by default in Japt). _  Pass each match through a function, where Z is the current element. °  The postfix increment operator (++). This converts Z to an integer without increasing it for the following operation. ç  Repeat a space character Z times. Implicitly output the resulting string. • Can m@ be shortened? – Oliver Aug 8 '17 at 15:02 • Not in this case, @Oliver; the m here is the multi-line flag for the regex, not the map method. – Shaggy Aug 8 '17 at 15:04 • @Oliver: r/^\d/m_î (or r/^\d/m_ç) would be 2 bytes shorter but Z is a string so, unfortunately, it wouldn't work. r/^\d/m_°ç, for a 1 byte saving, does work, though :) – Shaggy Aug 8 '17 at 15:15 • °ç is an amazing trick :-) I'd have suggested just \d for the regex, but that leaves out the flag... perhaps I should add support for flags on single-class regexes, like \dm (oh yeah, and that leaves out the ^ too...) – ETHproductions Aug 9 '17 at 1:55 • @ETHproductions, would it be feasible/possible to make the opening / optional in RegExes? – Shaggy Aug 10 '17 at 10:58 # Jelly, 19 bytes Ḣ⁶ẋ;µ¹µḣ1ẇØDµ? ỴÇ€Y  Try it online! -5 bytes total thanks to Jonathan Allan's comments and by looking at his post # Explanation Ḣ⁶ẋ;µ¹µḣ1ẇØDµ? Main link ? Ternary if if: ḣ1 the first 1 element(s) (Head would modify the list which is not wanted) ẇ is a sublist of (essentially "is an element of") ØD "0123456789" then: ẋ repeat ⁶ ' ' Ḣ n times where n is the first character of the line (head) ; concatenate the "beheaded" string (wording choice credited to Jonathan Allan) else: ¹ Identity (do nothing) µ µ µ Link separators ỴÇ€Y Executed Link Ỵ Split by newlines € For each element, Ç call the last link on it Y Join by newlines  • no need to swap arguments: Ḣ⁶ẋ; – Jonathan Allan Aug 8 '17 at 0:33 • The pop then head trick wont work if there is a line containing only a single digit character :( -- ;0Ḣ would work for one byte, maybe there is a single atom, I also tried ¹, no joy there – Jonathan Allan Aug 8 '17 at 1:14 • @JonathanAllan Ah right. Thanks. ḣ1ẇØD works for the same bytecount \o/ – HyperNeutrino Aug 8 '17 at 1:17 • ṚṪ will work :) – Jonathan Allan Aug 8 '17 at 1:17 • @JonathanAllan That works too :) But I made an explanation already for my method so I'm too lazy to change it :P But thanks anyway :) – HyperNeutrino Aug 8 '17 at 1:18 # Pyth, 16 15 bytes jm.x+*;shdtdd.z  Try it online! # Explanation jm.x+*;shdtdd.z - Full program that works by reading everything from STDIN. .z - Read all STDIN and split it by linefeeds. m - Map with a variable d. .x - Try: *;shd - To convert the first character to an Integer and multiply it by a space. + td - And add everything except for the first character d - If the above fails, just add the whole String. j - Join by newlines.  Let's take an example that should be easier to process. Say our input is: foo bar foo bar 1foo bar foo bar foo bar 2foo bar foo bar foo bar foo bar  The program above will do the following: • .z - Reads it all and splits it by newlines, so we get ['foo bar foo bar', '1foo bar foo bar foo bar', '2foo bar foo bar foo bar foo bar']. • We get the first character of each: ['f', '1', '2']. • If it is convertible to an integer, we repeat a space that integer times and add the rest of the String. Else, we just place the whole String. Hence, we have ['foo bar foo bar', ' foo bar foo bar foo bar', ' foo bar foo bar foo bar foo bar']. • Finally, we join by newlines, so our result is: foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar  • Haha, we beat Jelly :) – Mr. Xcoder Aug 8 '17 at 5:56 # Cubically, 82 bytes R3D1R1D1+0(?6{?7@7~:1+2<7?6{+35>7?6{:7-120?6{(B3@5B1-0)6}:0}}}?6!@7~-60=7&6+4-3=7)  Note: This will not work on TIO. To test this, use the Lua interpreter with the experimental flag set to true (to enable conditionals). There's currently a bug with conditional blocks on the TIO interpreter. When using the TIO interpreter, you should replace ?6! with !6 and &6 with ?6&, which keeps the byte count the same. R3D1R1D1 Set the cube so that face 0 has value 1 and the rest of the values are easy to calculate +0 Set the notepad to 1 so that it enters the conditional below ( Do ?6{ If the notepad is 1 (last character was \n or start of input) ?7@7 Output the current character if it's \n ~ Get the next character :1+2<7?6{ If the input is >= '0' +35>7?6{ If the input is <= '9' :7-120 Set the notepad to the input - '0' ?6{ If the notepad isn't 0 ( Do B3@5 Output a space B1-0 Subtract 1 from notepad )6 While notepad > 0 } End if :0 Set notepad to 1 } End if } End if } End if ?6!@7 If the notepad is 0 (did not attempt to print spaces), print current character ~ Get next character -60=7&6 If there is no more input, exit the program +4-3=7 Check if current character is \n, setting notepad to result ) Repeat forever  This isn't as short as the other Cubically answer, but I thought I'd give this a try anyway :D • What's going on with loops in the TIO interpreter? – MD XF Aug 9 '17 at 16:19 • @MDXF ) jumps to the most recent ( rather than the matching one I believe. EDIT: I'm in the chat. – TehPers Aug 9 '17 at 16:20 • @MDXF Maybe it was the conditional blocks, actually. I forgot, I'll update the answer. Regardless, they weren't matching up. – TehPers Aug 9 '17 at 16:22 • All right, I'll look at that later. I'm currently finishing Cubically 2. – MD XF Aug 9 '17 at 16:33 • @MDXF That's... really exciting to hear actually o_O – TehPers Aug 9 '17 at 16:35 # ><>, 60 bytes !^i:0(?;::"/")$":"(*0$. v"0"- >:?!v1-" "o ;>:o>a=&10&?.i:0(?  Try it online! ### How It Works: ..i:0(?;... Gets input and ends if it is EOF ... ... ... .^......::"/")$":"(*0$. If the inputted character is a digit go to the second line ... Else go to the fourth ... ... .... If it was a digit v"0"- Subtract the character "0" from it to turn it into the corresponding integer >:?!v1-" "o And print that many spaces before rejoining the fourth line ... .^.. On the fourth line, .... Copy and print the input (skip this if it was a digit) ....v If the input is a newline, go back to the first line. ;>:o>a=&10&?.i:0(? Else get the input, ending on EOF  # V, 9 bytes ç^ä/x@"é  Try it online! ### Explanation ç / ' On lines matching ^ä ' (Start)(digit) x ' Delete the first character @" ' (Copy Register) number of times é ' Insert a space  # Gema, 21 characters \N<D1>=@repeat{$1;\ }


Sample run:

bash-4.4$gema '\N<D1>=@repeat{$1;\ }' <<< 'foo bar foo bar
> 1foo bar foo bar foo bar
> 2foo bar foo bar foo bar foo bar
>
> --------v
> 8|
> 8|
> 80
> 8,
> 7&'
foo bar foo bar
foo bar foo bar foo bar
foo bar foo bar foo bar foo bar

--------v
|
|
0
,
&


# PHP, 83 chars

preg_replace_callback('/^\d/m',function($m){return str_repeat(' ',$m[0]);},$argv);  • I think your code is not compliant with the input rules of this challenge, you should enclose this in a function with a $s arg or populate it with the input. And it doesn't print anything – LP154 Aug 9 '17 at 12:01
• @LP154 is using argv acceptable? – Petah Aug 9 '17 at 23:36
• @Petah If I'm correct in assuming argv` is the command line args, then yes. – totallyhuman Aug 9 '17 at 23:42