8
\$\begingroup\$

Write a program or function that given some text, a number of columns, and the column width, formats the text into columns. This is plain text .

Rules

Input

  • The text will be a string of printable ASCII and may contain newlines and spaces (but not tabs).
  • The number of columns will be a positive integer.
  • The column width is an integer greater or equal to 2 that specifies how many characters per column.

For this challenge, a word will consist of any non-whitespace characters. The input consists of one string and two integers, which may be taken in any order.

Output

Output is the text formatted into balanced columns with as many words on each line as will fit.

  • If a word is too long to fit in a column, put the word on the next line if there is another word on the current line and the line could be padded to the column width with three spaces or less.
  • Otherwise, hyphenate the word so that it fills the rest of the line. Hyphenate wherever the line ends; don't worry about hyphenating between syllables.
  • Columns should be separated by a margin of four space characters.
  • The columns should be balanced so that they all have an equal number of lines if possible.
  • The leftmost columns should have an extra line if necessary.
  • Any line breaks and multiple spaces should be preserved. Trailing spaces are optional after the last column.

Examples

Text:

The number of columns will be a positive integer.  Columns should be separated by a margin of four space characters.

The columns should be balanced.  The column width is greater than two.

Columns: 3, width: 10

The number    separated     ns should 
of columns    by a marg-    be balanc-
will be a     in of four    ed.  The  
positive      space cha-    column wi-
integer.      racters.      dth is gr-
Columns                     eater than
should be     The colum-    two.      

Text:

This line is hyphenated.
This line, on the other hand, is not.  

Columns: 1, width: 20

This line is hyphen-
ated.               
This line, on the
other hand, is not.

Text: Tiny columns. columns: 4, width: 2

T-    c-    u-    s.
i-    o-    m-      
ny    l-    n-

Text: Two spaces.<space> columns: 5, width: 2

T-          p-    c-    s.
wo    s-    a-    e-

Text: <newline>A phrase columns: 2, width: 5

         rase
A ph-

Text: A short sentence. columns: 10, width: 5

A sh-    ort      sent-    ence.

Text: It's "no word" 1234567890 -+-+-+-+ (*&!) columns: 3, width: 6

It's      12345-    +-+
"no       67890     (*&!)
word"     -+-+--

This is ; standard rules apply.

\$\endgroup\$
  • \$\begingroup\$ Possible dupe \$\endgroup\$ – Mego Nov 17 '15 at 4:07
  • 4
    \$\begingroup\$ @Mego The challenges are related, however, this one requires hyphenating certain words and balancing columns, so I think it is different enough. \$\endgroup\$ – intrepidcoder Nov 17 '15 at 4:24
  • \$\begingroup\$ Is s:'tiny', c:4, w:2 = t- i- n- y or t- i- ny?? \$\endgroup\$ – TFeld Nov 20 '15 at 20:00
  • \$\begingroup\$ @TFeld My examples were wrong, it should be t- i- ny. Is everything right now, or do I need to fix it again? \$\endgroup\$ – intrepidcoder Nov 20 '15 at 21:02
  • \$\begingroup\$ Not sure, should tiny s be t- i- n- y_ s or t- i- ny s \$\endgroup\$ – TFeld Nov 20 '15 at 21:05
1
\$\begingroup\$

Python 2, 346 338 bytes

i,C,W=input()
r=[]
for l in [x or' 'for x in i.split('\n')]:
 while l:
  if' '==l[0]:l=l[1:]
  w=l[:W];x=W;s=w.rfind(' ')+1
  if max(W-3,0)<s:w=w[:s];x-=W-s
  elif x<len(l)and' 'not in l[x:x+1]:w=w[:-1]+'-';x-=1
  r+=[w];l=l[x:]
r=[s.ljust(W)for s in r+['']*(C-1)]
print'\n'.join('    '.join(s)for s in zip(*zip(*[iter(r)]*((len(r))/C))))

Input as 'string',C,W

\$\endgroup\$
  • \$\begingroup\$ Thanks, fixed by changing to rstrip(). \$\endgroup\$ – TFeld Nov 20 '15 at 21:48
  • \$\begingroup\$ Great! that saves me the strip() at the end. \$\endgroup\$ – TFeld Nov 20 '15 at 21:55
0
\$\begingroup\$

C++, 483

#include<vector>
#include<iostream>
#include<iomanip>
#define b t.push_back
#define r l.substr
using namespace std;int main(int n,char**a){int i=0,j,m,p,c=atoi(a[1]),w=atoi(a[2]);string l;vector<string>t;while(getline(cin,l))do{p=l.find_last_of(" \n",w);if(p!=string::npos&&p>w-4)b(r(0,p)),l=r(p+1);else if(l.length()<=w)b(l),l="";else b(r(0,w-1)+"-"),l=r(w-1);}while(l.length()>0);for(m=(c-1.+t.size())/c;i<m;cout<<"\n",i++)for(j=0;j<c;b(""))cout<<left<<setw(w+4)<<t[i+j++*m];}

I am sure it can be golfed more but I don't see anything right now.

\$\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.