27
\$\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\$
  • 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\$ – Timwi Sep 24 '15 at 0:39
  • \$\begingroup\$ Can there be spaces in the middle of an input line, e.g. Programming Puzzles\n&\nCode Golf? \$\endgroup\$ – Sp3000 Sep 24 '15 at 2:04
  • \$\begingroup\$ @sp3000 There can be any character, including spaces. \$\endgroup\$ – Trebuchette Sep 24 '15 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\$ – Peter Cordes Sep 24 '15 at 8:58

18 Answers 18

8
\$\begingroup\$

Pyth, 14 bytes

jm.[\ QdscRQ.z

Demonstration

Uses Pyth's pad operator.

\$\endgroup\$
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\$
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\$
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\$
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\$
  • \$\begingroup\$ 1. I'd include -r in the byte count. 2. f()(while ... done) is a bit shorter. \$\endgroup\$ – Dennis Sep 24 '15 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\$ – Peter Cordes Sep 24 '15 at 6:37
  • \$\begingroup\$ I recommend reading Tips for golfing in Bash. It's a great resource. \$\endgroup\$ – Dennis Sep 24 '15 at 6:39
  • \$\begingroup\$ Actually, since while is already compound, you don't even need the parentheses: f()while ... done \$\endgroup\$ – Dennis Sep 24 '15 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\$ – Peter Cordes Sep 24 '15 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.