68 · Text Justification

Greedy Packing, Even Spacing

Book typography justified text long before computers existed. This algorithm packs as many words as possible onto each line, then distributes the remaining whitespace evenly across the gaps — leftmost gaps absorb any remainder. The final line stays left-aligned, exactly like a paragraph's closing sentence.

MAX WIDTH


Three rules, one formatter

Every line follows exactly one of three spacing rules depending on its word count and position.

greedy packing

Keep adding words until the next word won't fit. Count each word's length plus one mandatory space between words. When the total exceeds the line width, stop and format.

space distribution

An interior line has totalSpaces = maxWidth − letters to spread across its gaps. Divide evenly: base = totalSpaces ÷ gaps, remainder extra = totalSpaces mod gaps. The leftmost gaps each absorb one extra space.

last line exception

The final line uses single spaces between words and pads the remaining width on the right — just like natural paragraph endings. A single-word line follows the same trailing-pad rule.


Pack, then format

Two phases per line. One greedy scan, one formatting pass.

  1. Greedy word scan

    Starting from the current word, accumulate words onto the line. A word fits if letters + word.length + gapCount ≤ maxWidth. Stop when the next word would overflow.

  2. Classify the line

    If only one word occupies the line, or this is the last line, use left-justification with trailing padding. Otherwise, use full justification with distributed spaces.

  3. Distribute spaces

    For interior lines: compute base = (maxWidth − letters) ÷ gaps and extra = (maxWidth − letters) mod gaps. Place base + 1 spaces in the first extra gaps, base in the rest.

  4. Emit and advance

    Append the formatted line to the output. Move the word pointer past the line's last word. Repeat until all words are consumed.


Where formatting rules collide

Three scenarios test whether you apply the right rule at the right time.

Single-word interior line

A word so long it fills the line alone. There are zero gaps — you cannot divide by zero. The word is left-justified with trailing spaces, exactly like a last line.

Uneven space distribution

When totalSpaces mod gaps ≠ 0, the leftmost gaps absorb the extras. For "one··two·six·ten": 4 spaces across 3 gaps gives base 1, extra 1. The first gap gets 2 spaces, the rest get 1.

Last line with multiple words

Even if there's room to distribute spaces evenly, the last line must use single spaces and pad the right. Treating it like an interior line would stretch words apart unnaturally.