(Note: This is my first ever code golf question, but as far as I can tell, nobody else has done exactly this, so I should be good.)

Your task is to make a program or function that takes in a string s and an integer n, and returns or outputs that text wrapped into multiple lines. Each word must be wholly on a line; i.e. no words split in the middle. Each line can be no longer than n characters long, and you must fit as many words as possible on each line.

Example:

s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus. Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non commodo nibh. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue. Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu, aliquam quis velit aliquam, dictum varius erat." 
n = 50

output:
Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Sed eget erat lectus. Morbi mi mi, fringilla
sed suscipit ullamcorper, tristique at mauris.
Morbi non commodo nibh. Pellentesque habitant
morbi tristique senectus et netus et malesuada
fames ac turpis egestas. Sed at iaculis mauris.
Praesent a sem augue. Nulla lectus sapien, auctor
nec pharetra eu, tincidunt ac diam. Sed ligula
arcu, aliquam quis velit aliquam, dictum varius
erat.

Your output can be an array of strings or a single string with line breaks. Also, you can assume no words will be longer than n, so don't worry about dealing with weird cases.

Standard I/O rules apply, and standard loopholes are prohibited. Trailing spaces are allowed.

Since this is , the shortes solution in bytes wins.

Here is an example program in Python that would work.

  • Format a list of words – user202729 Dec 1 at 1:49
  • 3
    n is the max line length ? or the length we have to reach before line break ? – david Dec 1 at 10:27
  • 1
    @david, or the number of lines? – Peter Taylor Dec 1 at 13:24
  • 1
    28 bytes Python is it relevant? – david Dec 1 at 14:12
  • 3
    n is the max line length, sorry that that was not clear. I will clarify. Also, the rules have now been updated so a simple split doesn't work. – ATMunn Dec 1 at 16:09

26 Answers 26

Python 2, 26 bytes

from textwrap import*
fill

Try it online!

Meh... built-ins are boring... instead, have a nice 87-byte solution here:

s,n=input()
x=''
for i in s.split():c=n<len(x+i);exec'print x'*c;x=x*-~-c+i+' '
print x

Try it online!

Outputs trailing spaces.

PHP, 8 bytes

Admittedly not the most original solution, but PHP has a native function that matches your requirements perfectly!

wordwrap:

string wordwrap ( string $str [, int $width = 75 [, string $break = "\n" [, bool $cut = FALSE ]]] )

Wraps a string to a given number of characters using a string break character.

Use like so:

$str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus. Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non commodo nibh. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue. Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu, aliquam quis velit aliquam, dictum varius erat.";
echo wordwrap($str, 50);

Or Try it online!

JavaScript (ES6),  75 73  72 bytes

Takes input as (string)(n).

s=>n=>s.split` `.map(w=>r=(u=r?r+' '+w:w)[n]?(o+=r+`
`,w):u,o=r='')&&o+r

Try it online!

Variables

The formatted output is stored in \$o\$ (in green below).

The updated line \$u\$ is defined as the concatenation of:

  • the current line \$r\$ (in black below)
  • a space if \$r\$ is not empty, or nothing otherwise (in orange below)
  • the new word \$w\$ (in blue below)

We need to insert a line break whenever the \$n\$-th character of \$u\$ is set (0-indexed, in red below).

Example

\$n=16\$ and \$s\$ = "LOREM IPSUM DOLOR"

Adding "LOREM": $$\small\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline 00&01&02&03&04&05&06&07&08&09&10&11&12&13&14&15&\color{red}{16}\\ \hline \color{blue}L&\color{blue}O&\color{blue}R&\color{blue}E&\color{blue}M&&&&&&&&&&&&\\ \hline\end{array} $$

Adding "IPSUM": $$\small\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline 00&01&02&03&04&05&06&07&08&09&10&11&12&13&14&15&\color{red}{16}\\ \hline L&O&R&E&M&\color{orange}\bullet&\color{blue}I&\color{blue}P&\color{blue}S&\color{blue}U&\color{blue}M&&&&&&\\ \hline\end{array} $$

Adding "DOLOR": $$\small\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline 00&01&02&03&04&05&06&07&08&09&10&11&12&13&14&15&\color{red}{16}\\ \hline L&O&R&E&M&\bullet&I&P&S&U&M&\color{orange}\bullet&\color{blue}D&\color{blue}O&\color{blue}L&\color{blue}O&\color{blue}R\\ \hline\end{array} $$

$$\small\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline 00&01&02&03&04&05&06&07&08&09&10&11&12&13&14&15&\color{red}{16}\\ \hline \color{green}L&\color{green}O&\color{green}R&\color{green}E&\color{green}M&\color{green}\bullet&\color{green}I&\color{green}P&\color{green}S&\color{green}U&\color{green}M&\color{green}\hookleftarrow&&&&&\\ \hline D&O&L&O&R&&&&&&&&&&&&\\ \hline\end{array} $$

  • Trailing spaces are allowed. maybe r+w+' '? – l4m2 Dec 3 at 0:24

Perl 6, 46 29 bytes

{;*.comb(/.**{1..$_}[\s|$]/)}

Try it online!

Regex based solution that takes input curried, like f(n)(s) and returns a list of lines. Each line except the last has a trailing whitespace

Explanation:

{;*                         }   # Anonymous code block that returns a Whatever lambda
   .comb(/                /)    # Split the string by
          .**{1..$_}            # Up to n characters
                    [\s|$]      # Terminated by a whitespace char or the end of the string

Vim, 15 bytes/keystrokes

DJ:se tw=<C-r>"
gq_

A text formatting question? I know just the tool for the job! And it even has my name in the first two keystrokes :D

<C-r> means ctrl-r.

This could ever so slightly shorter in V, but I prefer answering in vanilla vim for answers that really show off how concise vim can be for the right challenge. And the difference is so small anyway.

This could also be the following for 15 bytes as well:

:se tw=<C-r><C-w>
ddgq_

Try it online!

  • 1
    Explanation: DJ:: This program has been made by DJ, our favorite cat with a diamond around his neck. [...] – Erik the Outgolfer Dec 1 at 19:10

R, 36 27 bytes

R has this as a built-in (strwrap), we return a vector of split lines.

function(s,n)strwrap(s,n+1)

Try it online!

  • 1
    Yes, that should be allowed. Arrays of lines are allowed, so I don't see why this would be any different. – ATMunn Dec 1 at 16:14

Haskell, 70 bytes

s!n|length s<=n=[s]|(t,_:d)<-splitAt(until((<'!').(s!!))pred n)s=t:d!n

Python 2, 74 bytes

s,n=input()
while s:i=n;exec"i-=' '<(s+' '*n)[i];"*n;print s[:i];s=s[i+1:]

Try it online!

Java (JDK), 46 44 bytes

Basically a pure regex solution in Java, almost certainly the shortest I've written.

Cheers to Kevin for helping to cut down the bytes in the regex even further!

n->s->s.replaceAll(".{1,"+n+"}( |$)","$0\n")

Try it online!

Using a curried lamdba, it creates a regex to greedily match up to n characters followed by either a space or end of string. It then replaces those characters with themselves followed by a newline.

  • @KevinCruijssen [ $] actually just matches a space or $ if I remember correctly, rather than the end of string. It does seem to work though, so it looks like it can just be golfed down to a single space for even fewer bytes. – Luke Stevens Dec 5 at 10:36
  • Ah, it can indeed be just a space, since you add newlines and don't need to add an additional trailing newline at the end. – Kevin Cruijssen Dec 5 at 10:38
  • 1
    You can golf 2 more bytes removing the parenthesis in the regex, and use $0 instead of $1. – Kevin Cruijssen Dec 5 at 10:44
  • @KevinCruijssen Nice one! It's just a shame that replaceAll is so verbose! – Luke Stevens Dec 5 at 10:53
  • 2
    For me it is wrong, appear if I modify the Latin phrase of the exercise in the way it end with"...dictum varius a b c erat." There is a unnecessary new line after c letter... – RosLuP Dec 5 at 17:00

Mathematica, 16 bytes

InsertLinebreaks

Built-in function. Takes a string and an integer as input and returns a string as output.

InsertLinebreaks["string", n]
 inserts newline characters to make no line longer than n characters.

C (gcc), 68 bytes

i;b(s,n,l)char*s,*l;{for(i=n;*++s;i--||(i=l-s+n,*l=10))l=*s-32?l:s;}

Try it online!

Thanks to ceilingcat, save 2 bytes by moving global char*l to parameter.

Retina 0.8.2, 37 bytes

.+$
$*
!`(?=\S.*¶(1)+)(?<-1>.)+(?=\s)

Try it online! Takes s and n on separate lines. Explanation:

.+$
$*

Convert n to unary.

(?=\S.*¶(1)+)(?<-1>.)+(?=\s)

Match non-whitespace, then look ahead to n and count it as $#1. Then go back and use a balancing group to match up to n characters followed by whitespace.

!`

Output the matches as a list of lines.

  • Is there a way in Retina to put the first input in a regex we use with the second input? So something like this: .{1,50} and $0¶, but where 50 is received as input instead? – Kevin Cruijssen Dec 5 at 10:55
  • @KevinCruijssen In Retina 1 you can probably use an Eval stage to give a similar result, but that's boring, so I didn't bother. – Neil Dec 5 at 14:04

Charcoal, 19 bytes

Nθ←F⪪S «¿‹⁺LιⅈθM→⸿ι

Try it online! Link is to verbose version of code. Takes input of n and s on separate lines. Explanation:

Nθ

Input n.

Move the cursor left one square to balance the right movement from the first iteration of the loop.

F⪪S «

Split the string on spaces and loop over the words.

¿‹⁺Lιⅈθ

Calculate whether the next word will reach the right edge.

M→

If it will not then move one square right.

⸿

If it will then start a new line.

ι

Output the word.

Red, 125, 117, 114 112 bytes

func[s n][d: 0 parse s[any[to" "p:" "opt[[to" "| to end]q:(if(-1 - d + index? q)> n[p/1: #"^/"d: index? p])]]]s]

Try it online!

Powershell, 40 83 bytes

Test case with n=80 added.

param($s,$n)$s-split' '|%{if(($o+$_|% le*)-lt$n){$o+=' '*!!$o+$_}else{$o;$o=$_}}
$o

Test script:

$f = {

param($s,$n)$s-split' '|%{if(($o+$_|% le*)-lt$n){$o+=' '*!!$o+$_}else{$o;$o=$_}}
$o

}

@(
,(50, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus. Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non commodo nibh. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue. Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu, aliquam quis velit aliquam, dictum varius erat.",
"Lorem ipsum dolor sit amet, consectetur adipiscing",
"elit. Sed eget erat lectus. Morbi mi mi, fringilla",
"sed suscipit ullamcorper, tristique at mauris.",
"Morbi non commodo nibh. Pellentesque habitant",
"morbi tristique senectus et netus et malesuada",
"fames ac turpis egestas. Sed at iaculis mauris.",
"Praesent a sem augue. Nulla lectus sapien, auctor",
"nec pharetra eu, tincidunt ac diam. Sed ligula",
"arcu, aliquam quis velit aliquam, dictum varius",
"erat.")
,(80, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus. Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non commodo nibh. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue. Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu, aliquam quis velit aliquam, dictum varius erat.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus.",
"Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non",
"commodo nibh. Pellentesque habitant morbi tristique senectus et netus et",
"malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue.",
"Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu,",
"aliquam quis velit aliquam, dictum varius erat.")
) | %{
    $n,$s,$expected = $_
    $result = &$f $s $n
    "$result"-eq"$expected"
    # $result   # uncomment this line to dispaly a result
}

Output:

True
True

Java 8, 135 bytes

n->s->{String r="",S[]=s.split(" "),t=r;for(int i=0;i<S.length;)if((t+S[i]).length()>n){r+=t+"\n";t="";}else t+=S[i++]+" ";return r+t;}

Try it online.

Explanation:

n->s->{                      // Method with integer & String parameters and String return
  String r="",               //  Result-String, starting empty
         S[]=s.split(" "),   //  Input-String split by spaces
         t=r;                //  Temp-String, starting empty as well
  for(int i=0;i<S.length;)   //  Loop `i` in the range [0, amount_of_words):
    if((t+S[i]).length()>n){ //   If `t` and the word are larger than the integer input:
      r+=t+"\n";             //    Add `t` and a newline to the result
      t="";}                 //    And reset `t` to an empty String
     else                    //   Else:
       t+=S[i++]+" ";        //    Append the word and a space to `t`
                             //    (and then increase `i` by 1 with `i++` for the next word
                             //     of the next iteration)
  return r+t;}               //  Return the result-String appended with `t` as result

Japt, 24 bytes

¸r@[XY]q(X·Ì+S+Y Ê>V?R:S

Try it online!

Thanks to Bubbler for removing some duplication.

Explanation:

¸                           :Split into words
 r@                         :Reduce back into a string by:
         X                  : Start with the already reduced portion
          ·Ì                : Get the last line
            +S+Y            : Add a space and the next word
                 Ê>V?       : If the length of that line is greater than n:
                     R      :  Choose newline
                      :     : Otherwise:
                       S    :  Choose space
   [XY]q(                   : Join the next word to the result using the chosen character

JavaScript, 40 bytes

s=>n=>eval(`s.match(/.{1,${n}}( |$)/g)`)

Try it online!

  • Fail at the end – l4m2 Dec 3 at 4:26
  • @l4m2 fixed.... – tsh Dec 3 at 5:02

Thanks to @Erik the Outgolfer, a golfed version :

Python 3, 94 bytes

def f(t,n):
 while t:i=n+(t[min(len(t)-1,n)]==" "or-t[n-1::-1].find(' '));print(t[:i]);t=t[i:]

Try it online!

# Python 3, 130 bytes

def f(t,n):
 l=[]
 while len(t):
  i=(n-t[:n][::-1].find(' '),n+1)[t[min(len(t)-1,n)]==" "]
  l.append(t[:i])
  t=t[i::]
 return l

Try it online!

Not so golfed version...

JavaScript + HTML + CSS, 117 64 bytes

-53 bytes courtesy of @Neil

n=50
s="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget erat lectus. Morbi mi mi, fringilla sed suscipit ullamcorper, tristique at mauris. Morbi non commodo nibh. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed at iaculis mauris. Praesent a sem augue. Nulla lectus sapien, auctor nec pharetra eu, tincidunt ac diam. Sed ligula arcu, aliquam quis velit aliquam, dictum varius erat."
f=(n,s)=>document.body.innerHTML+=`<tt><p style=width:${n}ch>${s}`
f(n,s)

  • 1
    At least in my browser you can cut this down to (n,s)=>document.body.innerHTML+=`<p style=width:${n}ch><tt>${s}</tt></p>` for 74 bytes. If you're willing to dig out old versions of Firefox you can save another 8 bytes with (n,s)=>document.body.innerHTML+=`<pre wrap width=${n}>${s}</pre>` . – Neil Dec 1 at 12:33
  • @Neil Nice use of ch units. Firefox 65 computes 50ch as 500px; Chromium 70 computes 50ch as 400px – guest271314 Dec 1 at 18:28
  • This answer is wrong. elit. Sed eget erat lectus. Morbi mi mi, fringilla sed (2nd line) is more than 50 characters. I'm using the newest Chrome. – mbomb007 Dec 1 at 19:59
  • I was able to tweak my original suggestion to work in Chrome by putting the <p> inside the <tt>. – Neil Dec 1 at 20:16
  • 1

Jelly, 12 bytes

ḲŒṖK€€ḣ€ƑƇṪY

Try it online!

Unfortunately, this is too slow to work for the provided test case in under a minute over TIO.

C# (.NET Core), 162 bytes

string[]t(string n,int a){var g="";for(int i=0;i++<Math.Floor((double)n.Length/a);)g+=$"^.{{{i*a-1}}}|";return Regex.Split(n,$@"(?n)(?<=({g.Trim('|')})\S*)\s");}}

This function uses a regex which matches the closest whitespace that is near the nth or multiple of nth character and splits the string based on it.

Try it online!

The TIO link is a full program, and the function has a static keyword so the function can be called from main.

Test Regex

  • This doesn't give the right output for the test case - some lines are longer than 50 characters. You want "before" not "near", and also the splitting at one point must depend on where it was split earlier. – Ørjan Johansen Dec 3 at 9:14

05AB1E, 18 bytes

õs#vDy«g²›i,}yðJ}?

Try it online.

Explanation:

õ                   # Push an empty string "" to the stack
 s                  # Swap to take the (implicit) string input
  #                 # Split it by spaces
   v            }   # For-each `y` over the words:
    D               #  Duplicate the top of the stack
                    #  (which is the empty string in the very first iteration)
     y«             #  Append the current word `y`
       g            #  Get its length
        ²›i }       #  If its lengthy is larger than the second input:
           ,        #   Pop and output the current duplicated value with trailing newline
             yð     #  Push the word `y` and a space " "
               J    #  Join the entire stack together
                 ?  # After the loop, output the last part as well (without newline)

C# (Visual C# Interactive Compiler), 78 bytes

s=>n=>System.Text.RegularExpressions.Regex.Replace(s,".{1,"+n+"}( |$)","$0\n")

Try it online!

Credit goes to @LukeStevens for coming up with the Java version... Apparently .NET makes you import the RegularExpressions namespace in order to do a replace :(

Here is my original version that splits on the space character and uses LINQ to join them back together:

C# (Visual C# Interactive Compiler), 91 bytes

s=>n=>s.Split(' ').Aggregate((a,w)=>a+(a.Length-a.LastIndexOf('\n')+w.Length>n?'\n':' ')+w)

Try it online!

Dart, 112 bytes

f(s,n){var l=[''];s.split(' ').forEach((w){if((l.last+w).length<=n)l.last+=w+' ';else l.add(w+' ');});return l;}

Try it online!

C, 81 bytes

b(a,n)char*a;{int c,i,j;for(c=i=0;c++>n&&(a[i=j]=10,c=0),j=a[i]-32?j:i,a[i++];);}

The function of this exercise b(a,n) would break the line "a" as exercise said, in the way not change its length (if we see the result as one string) because change some spaces in \n or new line in place. The input string "a" should have no \n character too in it for b() function (it could have \n in input string for bs())

b(a,n) function would be ok only because the restriction of this exercise, that impose each word of "a" string has length < n if this is not true, that function can go
to one infinite loop...(very wrong in my way of see so i copy too the function more good because in that case would return -1 and not would go to one infinite loop; it is bs(a,n) below)I not exclude both functions are bugged...

#define R(x,y) if(x)return y
#define U unsigned
U bs(char*a,U n)
{U c,q,r=1,i,j;
 R(!a||n<1||n++>0xFFFF,-1);
 for(j=c=i=0;;++i,++c)
    {R(i==-1,-1);q=a[i];
     if(q==10)goto l;
     if(c>=n){R(i-j>n,-1);a[i=j]=10;l:c=-1;++r;}
     R(!q,r);
     if(q==32)j=i;
    }
}

result of b() passed on one function that add line lenght each line

Lorem ipsum dolor sit amet, consectetur adipiscing [50]
elit. Sed eget erat lectus. Morbi mi mi, fringilla [50]
sed suscipit ullamcorper, tristique at mauris. [46]
Morbi non commodo nibh. Pellentesque habitant [45]
morbi tristique senectus et netus et malesuada [46]
fames ac turpis egestas. Sed at iaculis mauris. [47]
Praesent a sem augue. Nulla lectus sapien, auctor [49]
nec pharetra eu, tincidunt ac diam. Sed ligula [46]
arcu, aliquam quis velit aliquam, dictum varius [47]
erat. [5]
  • @ceilingcat ok, above code would make in consideration the \n too... one bug I found with the code was that the last line was not correctly print... why do you not write your C answer as other? It would win on mine because it is more short... for say the true I use the first line(or statement ";") for the check of input only because for me input has to be checked even if that is a little more long; I unsuccessful try to write the function in APL... – RosLuP Dec 5 at 11:05
  • @ceilingcat in the last answer, seen that question not say if the input string have or not have to have in it '\n' char and seen that example not has '\n' I suppose input string has no new line character in it... – RosLuP Dec 11 at 20:34
  • 1
    80 bytes – ceilingcat Dec 12 at 3:45
  • Only 83 ... Yes I have to see if I gain 3 chars using old function definition... – RosLuP Dec 12 at 20:05
  • Just 81 .... .... .... – RosLuP Dec 12 at 20:20

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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