Is there are text wrapping library for Elixir?

Hello everybody,

I’m new to elixir and I don’t find a text wrapping library, something
like Python textwrap.

Is it missing ? If yes, is there a will to have it ?

Cheers

Welcome,

The best way to search for a specific lib is to look at hex.pm

For example… with text as search key.

I am not sure this one compares to TextWrap, but it seems to help with text format.

You might also enjoy this read, if You are in the mood of rewriting it, and don’t mind reading some Erlang code.

https://pragdave.me/blog/2007/04/19/testfirst-word-wrap-in-erlang.html

2 Likes

Be aware of the big wrapping dangers of Unicode. U+FDFD is a single very wide character: ﷽ in some fonts, and a reasonably large one in others. Ask your library to wrap, and if it has no knowledge of font widths (and you’re not using a monospace font), you’ll end up with lines that are guaranteed to blow everything up.

I would generally maintain healthy skepticism when someone attempts to wrap text without knowing how it is going to be rendered, although the rest of the functionality of the textwrap module in python are quite useful.

2 Likes

I haven’t seen nor found any that do exactly what you want, but the algorithm isn’t terribly complicated; with a bit of recursion you can actually accomplish it pretty quickly.

Of particular note is the Knuth-Pass line-wrap algorithim

RosettaCode shows this implementation of a line wrapper:

defmodule Word_wrap do
  def paragraph( string, max_line_length ) do
    [word | rest] = String.split( string, ~r/\s+/, trim: true )
    lines_assemble( rest, max_line_length, String.length(word), word, [] )
      |> Enum.join( "\n" )
  end
 
  defp lines_assemble( [], _, _, line, acc ), do: [line | acc] |> Enum.reverse
  defp lines_assemble( [word | rest], max, line_length, line, acc ) do
    if line_length + 1 + String.length(word) > max do
      lines_assemble( rest, max, String.length(word), word, [line | acc] )
    else
      lines_assemble( rest, max, line_length + 1 + String.length(word), line <> " " <> word, acc )
    end
  end
end
 
text = """
Even today, with proportional fonts and complex layouts, there are still cases where you need to 
wrap text at a specified column. The basic task is to wrap a paragraph of text in a simple way in
your language. If there is a way to do this that is built-in, trivial, or provided in a standard 
library, show that. Otherwise implement the minimum length greedy algorithm from Wikipedia.
"""
Enum.each([72, 80], fn len ->
  IO.puts String.duplicate("-", len)
  IO.puts Word_wrap.paragraph(text, len)
end)

@kokolegorille thanks for the tip and the link
@ferd I know perfect wrapping text is a complex problem, but most of the time a not so good wrapping is good enough
@Paradox thanks for the link