28
\$\begingroup\$

Your job is to take a string input and a number and align the string to the right, making the width of the text the number. When a line is too long, break it and put the rest on the next line, repeating until it's not necessary. If a line is shorter than the width, then pad it with spaces. Multiple newlines can occur, and should be treated like any other single character.

For example, the string

Programming Puzzles & Code Golf 

and the number 5 would produce:

Progr ammin g Puzzl es & Code Golf 

Whereas the same string and the number 10 would produce:

Programmin g Puzzles & Code Golf 

The string

a b 

and the number 5 would produce:

 a <-- note the 5 spaces b 

Shortest code wins!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ The text says “Break the lines when necessary [...]”, but your examples suggest that you break after every word, even when it would fit. Please clarify: do we place each word on a new line, or do we implement an actual word-wrapping algorithm? \$\endgroup\$ Commented Sep 24, 2015 at 0:39
  • \$\begingroup\$ Can there be spaces in the middle of an input line, e.g. Programming Puzzles\n&\nCode Golf? \$\endgroup\$ Commented Sep 24, 2015 at 2:04
  • \$\begingroup\$ @sp3000 There can be any character, including spaces. \$\endgroup\$ Commented Sep 24, 2015 at 2:08
  • \$\begingroup\$ @Timwi: The example has one word per line. It would have been better to include some multi-word lines to make it clear that space within a line isn't special. (i.e. there are only newlines, and non-newlines.) \$\endgroup\$ Commented Sep 24, 2015 at 8:58
  • \$\begingroup\$ Do 5 char take 1 or 2 lines? \$\endgroup\$ Commented Aug 8, 2023 at 8:44

18 Answers 18

10
\$\begingroup\$

Python 2, 84

s,n=input() for w in s.split('\n'): w=w or' ' while w:print w[:n].rjust(n);w=w[n:] 

Takes as input a string with newlines and a number, and prints the result. For each line in the input, takes and prints n chars at a time, using the built-in rjust to pad the left with spaces before printing.

I fixed the empty line case with the hack w=w or' '. There's probably a better method but I'm not going to think much about it.

\$\endgroup\$
0
8
\$\begingroup\$

Pyth, 14 bytes

jm.[\ QdscRQ.z 

Demonstration

Uses Pyth's pad operator.

\$\endgroup\$
8
\$\begingroup\$

CJam, 21 bytes

li_qN/Sfe|f/ff{\Se[N} 

Thanks to @Sp3000 for golfing off 1 byte and paving the way for 3 more.

Try it online in the CJam interpreter.

How it works

li Read an integer L from the first line of input. _ Push a copy. qN/ Split the remaining input at linefeeds. Sfe| Map `OR " "'; the replaces empty lines with a space. f/ Split each line into chunks of length L. ff{ } For each chunk, push L and the chunk; then: \ Swap L with the chunk. Se[ Left-pad the chunk to length L by prepending " ". N Push a linefeed. 
\$\endgroup\$
0
5
\$\begingroup\$

Pyth, 16

jm>Q+*\ QdscRQ.z 

Try it online here

Explanation

jm>Q+*\ QdscRQ.z : Q is the number on the first line, .z takes the rest cRQ.z : chop each line of .z into chunks of Q characters m s : remove nested lists and map over the result +*\ Qd : add Q spaces to each line d >Q : take the last Q characters of that result j : join results on newlines 
\$\endgroup\$
4
\$\begingroup\$

Perl, 39 bytes

perl -ni5 -e 's!^$|.{1,$^I}!printf"%${^I}s ",$&!ge' 

36 bytes + 3 bytes for -ni. The wrap width is passed as the argument to -i.

Handles blank lines properly by padding them with spaces:

$ echo -e "Programming\nPuzzles\n\n&\n\nCode\nGolf" | perl -ni5 -e 's!^$|.{1,$^I}!printf"%${^I}s ",$&!ge' Progr ammin g Puzzl es & Code Golf 

How it works

This solution uses the substitution operator to loop through the input, saving a byte over the equivalent for loop. The real trick, though, is in the regex on the LHS of the substitution:

^$|.{1,$^I} 

With the global modifier, this will match $^I characters at a time; when there are less than $^I characters remaining in the string, it will match everything to the end. The alternation with ^$ is required to handle blank lines. For example:

$ echo -e "foo\n\nbar" | perl -ni2 -E 'say "<$_>" for /^$|.{1,$^I}/g' <fo> <o> <> <ba> <r> 

The RHS of the substitution simply uses printf to left-pad the matched chunk with spaces.

\$\endgroup\$
2
  • \$\begingroup\$ I always forget about $^I! \$\endgroup\$ Commented Sep 24, 2015 at 20:59
  • \$\begingroup\$ @DomHastings I learned that trick from chilemagic, who mentioned it in a comment on another challenge. \$\endgroup\$ Commented Sep 24, 2015 at 21:11
3
\$\begingroup\$

Javascript (ES6), 107

I wish JS had a built in pad function. Oh well.

(a,b)=>a.replace(eval(`/(.{${b}})(?!\\n)/g`),`$1 `).split` `.map(c=>(Array(b).join` `+c).slice(-b)).join` ` 

Explanation:

(a, b)=> // searches for sequences of characters longer than b without a newline after them and // adds a newline after every b characters of the sequence a.replace(eval(`/(.{${b}})(?!\\n)/g`), '$1\n') .split('\n') .map(c=> // prepends b spaces to each string then slices it from the right down to length b ( Array(b).join(' ') + c ).slice(-b) ).join('\n') 
\$\endgroup\$
3
\$\begingroup\$

Julia, 126 bytes

f(s,n)=for i=split(s,"\n") while length(i)>0 println(lpad(i[1:min(n,end)],n));length(i)<n?break:(i=i[min(n+1,end):end])end;end 

Ungolfed:

function f(s::String, n::Int) for i in split(s, "\n") while length(i) > 0 println(lpad(i[1:min(n,end)], n)) length(i) < n ? break : (i = i[min(n+1,end):end]) end end end 
\$\endgroup\$
2
\$\begingroup\$

Bash, 62, 61+feature, 59

Shorter if N can be set by the caller, instead of having to read it as the first line of input.

# width as a function arg: 59 chars f()while read -rn$1 r;do [[ $r ]]&&printf %$1s\\n "$r";done # width on stdin: 64 chars (not updated with later suggestions&ideas) read N;while read -rn$N r;do [[ $r ]]&&printf %$N's\n' "$r";done 

This fails to handle empty lines in the input. Otherwise, this doesn't subject the input data to word-splitting, pathname expansion, or otherwise treat it as more than just raw data.

read -n$N saves one character, but lets read munge \.

The [[ $r ]]&& is needed because read -n4 can't lookahead to see that the next char is a newline. So it sets r to a 4-char string, and the next read produces a zero-char empty string. Filtering these false newlines without filtering real newlines would require tracking state: whether the previous line was max-length or not. Either more code or a totally different approach would be needed.

[[ $r ]] is shorter than [ -n "$r" ] which is needed to avoid errors if the line starts with -z foo, or is * or something, if you used [ $r ].

Justication happens with the standard printf "%4s" format string.

Test with

f()(while read -rn$1 r;do [[ $r ]]&&printf %$1s\\n "$r";done); (echo 4; echo -e "*\n\\"; cat /tmp/lines) | f 4 
\$\endgroup\$
5
  • \$\begingroup\$ 1. I'd include -r in the byte count. 2. f()(while ... done) is a bit shorter. \$\endgroup\$ Commented Sep 24, 2015 at 6:36
  • \$\begingroup\$ @Dennis: Without [[ $r ]]&&, if N=4, an input line of length 4 will produce a blank output line where there wasn't one before. Because read returns a string of 4 chars, then sees a newline on the next call and returns right away. Also, thanks for the () tip. I didn't know you could define fns that way. \$\endgroup\$ Commented Sep 24, 2015 at 6:37
  • \$\begingroup\$ I recommend reading Tips for golfing in Bash. It's a great resource. \$\endgroup\$ Commented Sep 24, 2015 at 6:39
  • \$\begingroup\$ Actually, since while is already compound, you don't even need the parentheses: f()while ... done \$\endgroup\$ Commented Sep 24, 2015 at 6:42
  • \$\begingroup\$ @Dennis: wow, haxx. Thanks for the link. A couple of those things were new to me, and I fixed a couple things in another answer :) I don't normally golf, but >15 years of being a command-line junkie has taught me a thing or two :) \$\endgroup\$ Commented Sep 24, 2015 at 7:18
2
\$\begingroup\$

Haskell, 108 bytes

import Data.List.Split k[]=[""] k x=x f n=unlines.(map(\l->([1..n-length l]>>" ")++l).k.chunksOf n=<<).lines 

Usage example:

*Main> putStr $ f 5 "a\n\nb\ncd\nMatamorphosis" a b cd Matam orpho sis 

How it works

 .lines -- split input string at newlines =<< -- for every line chunksOf n -- split into chunks of length n k -- fix empty lines map -- for every chunk \l->([1..n-length l]>>" " -- make a string of missing spaces ++l -- and append the chunk unlines -- join padded chunks with newlines in-between 
\$\endgroup\$
1
\$\begingroup\$

GNU awk + bash, 70

f()(awk -vFPAT=.\{,$1} '{for(i=0;i++<NF;){printf "%'$1's\n",$i}}/^$/') 

Using bash to slot the count into the awk program is prob. smaller than reading it with a NR==1{N=$0} block.

Read a line at a time. Split into at-most-4 character chunks, using FPAT. (matches the fields, rather than the separators. GNU extension.) printf each field separately. (Default ORS = \n).

The /^$/ rule is there to print empty lines, which have NF=0 and thus don't print at all in the other block. So unlike my pure-bash solution, this actually works in the general case.

Semi-unrelated, but my idea so far for perl is 112 chars for just the perl code:

(echo 4; echo -e 'foo\nbar'; echo -e "*\n\\"; echo '~$(true)'; cat /tmp/lines) | # test input perl -e '$N=<>;$/=\1;print "$N\n"; while(<>){if(/\n/ or length($l)>=$N){printf("%$4s\n",$l);$l=/\n/?"":$_;}else{$l.=$_;}}' 

This eats one of the newlines, and is way too long. $/=\1 reads a byte at a time. We append to $l. Probably a line-at-a-time with fixed-width split approach would be shorter.

\$\endgroup\$
1
\$\begingroup\$

Bash + GNU utils, 41

fold -$1|sed ":;s/^.\{,$[$1-1]\}\$/ &/;t" 

String is input via STDIN, width is input by command-line arg:

ubuntu@ubuntu:~$ echo 'Programming Puzzles & Code Golf'|./ralign.sh 10 Programmin g Puzzles & Code Golf ubuntu@ubuntu:~$ 
\$\endgroup\$
1
\$\begingroup\$

Python 2, 151 bytes

s,n=input();N='\n' for w in[i.lstrip()if i.replace(' ','').isalpha()else i for i in s.replace(N,'\n ').split(N)]: while w:print w[:n].rjust(n);w=w[n:] 

This is a adaptation of @xnor's answer above, as his does not properly handle newlines.


The for loop was changed from:

for w in s.split('\n'): 

to:

for w in[i.lstrip()if i.replace(' ','').isalpha()else i for i in s.replace(N,'\n ').split(N)]: 

Example

$ python main.py "Programming\n\n\nPuzzles\n\n&\n\nCode\nGolf", 5 Progr ammin g Puzzl es & Code Golf 
\$\endgroup\$
1
\$\begingroup\$

C#, 143 bytes

(s,n)=>Join("\n",s.Split('\n').SelectMany(l=>(l.Any()?l:" ").Select((c,i)=>new{c,i}).GroupBy(o=>o.i/n,o=>o.c).Select(g=>Concat(g).PadLeft(n)))) 

Linq lets you make pretty gnarly expressions. GroupBy is useful here, but it's a shame they couldn't create function overloads taking the index.

Assign the lambda to a Func<string, int, string> to run it

Less golfed:

Func<string, int, string> Align = (s, n) => Join("\n", s.Split('\n') .SelectMany(l => (l.Any() ? l : " ") .Select((c, i) => new { c, i }) .GroupBy(o => o.i / n, o => o.c) .Select(g => Concat(g).PadLeft(n)))); 
\$\endgroup\$
1
\$\begingroup\$

Groovy, 63 bytes

Returns the correctly alligned string. Didn't know there was a padLeft (and padRight, padCenter) function until now.

f={s,n->s.split("(?<=\\G.{$n})|\n")*.padLeft(n," ").join("\n")} 
\$\endgroup\$
1
\$\begingroup\$

JavaScript 174 136

function R(s,x){return s.replace(new RegExp(".{"+x+"}","g"),"$&\n").replace(/[^\n]*/g,function(m){ while(m.length<x)m=" "+m;return m;})} 
\$\endgroup\$
1
\$\begingroup\$

Ceylon, 107

String w(String s,Integer n)=>"\n".join{for(l in s.lines)for(p in l.partition(n))String(p).padLeading(n)}; 
\$\endgroup\$
1
\$\begingroup\$

Matlab, 99 bytes

Thanks to @beaker for removing 6 bytes!

Using and anonymous function:

@(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0))) 

Define the function and use ans to call it:

>> @(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0))) ans = @(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0))) >> ans(['Programming' 10 'Puzzles' 10 '&' 10 'Code' 10 'Golf'], 5) %% 10 is line feed ans = Progr ammin g Puzzl es & Code Golf 
\$\endgroup\$
1
\$\begingroup\$

Burlesque, 28 Bytes

Same as the version below, but treats line 1 as the number and the other lines as the string.

lng_riPpun{pPco{pP' lp}mu}Wl 

Usage as in:

$ cat input.txt | blsq --stdin "lng_riPpun{pPco{pP' lp}mu}Wl" Progr ammin g Puzzl es & Code Golf 

Old Version (16 bytes):

{5co{5' lp}mu}Wl 

Example:

blsq ) "Programming\nPuzzles\n&\nCode\nGolf"{5co{5' lp}mu}Wl Progr ammin g Puzzl es & Code Golf 
\$\endgroup\$
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.