2

Is there a library that takes care of converting digits to words?
For example :
convert 103 -> One hundred and three
or convert 5765 -> Five thousand seven hundred and sixty-five

fay
  • 2,086
  • 2
  • 14
  • 36
  • 1
    I am not aware of any library doing this. A possible algorithm (here given in java) can be found on on https://stackoverflow.com/questions/3911966/how-to-convert-number-to-words-in-java – Arno Mittelbach Jul 30 '17 at 14:46

2 Answers2

4

Not published to Hex.pm, but here's a gist of a module that implements a number to words algorithm:

iex(2)> NumberToWord.say(123312133123)
"one hundred and twenty three billion, three hundred and twelve million, one hundred and thirty three thousand, one hundred and twenty three"

Source:

defmodule NumberToWord do
  @spec say(integer) :: String.t
  def say(n), do: n |> say_io() |> IO.iodata_to_binary()

  @spec say_io(integer) :: iodata
  def say_io(1), do: "one"
  def say_io(2), do: "two"
  def say_io(3), do: "three"
  def say_io(4), do: "four"
  def say_io(5), do: "five"
  def say_io(6), do: "six"
  def say_io(7), do: "seven"
  def say_io(8), do: "eight"
  def say_io(9), do: "nine"
  def say_io(10), do: "ten"
  def say_io(11), do: "eleven"
  def say_io(12), do: "twelve"
  def say_io(13), do: "thirteen"
  def say_io(14), do: "fourteen"
  def say_io(15), do: "fifteen"
  def say_io(16), do: "sixteen"
  def say_io(17), do: "seventeen"
  def say_io(18), do: "eighteen"
  def say_io(19), do: "nineteen"
  def say_io(20), do: "twenty"
  def say_io(30), do: "thirty"
  def say_io(40), do: "forty"
  def say_io(50), do: "fifty"
  def say_io(60), do: "sixty"
  def say_io(70), do: "seventy"
  def say_io(80), do: "eighty"
  def say_io(90), do: "ninety"
  def say_io(n) when n < 100 do
    tens = div(n, 10) * 10
    remainder = rem(n, 10)
    format(tens, "", " ", remainder)
  end
  def say_io(n) when n < 1000 do
    hundreds = div(n, 100)
    remainder = rem(n, 100)
    format(hundreds, " hundred", separator(remainder), remainder)
  end
  ~w[thousand million billion trillion quadrillion quintillion sextillion septillion octillion nonillion decillion]
  |> Enum.zip(Stream.unfold(1000, fn acc -> {acc, acc * 1000} end))
  |> Enum.each(fn {suffix, m} ->
    def say_io(n) when n < (unquote(m) * 1000) do
      number = div(n, unquote(m))
      remainder = rem(n, unquote(m))
      format(number, " " <> unquote(suffix), separator(remainder), remainder)
    end
  end)

  @spec separator(integer) :: String.t
  def separator(remainder) when remainder < 100, do: " and "
  def separator(_remainder), do: ", "

  @spec format(integer, String.t, String.t, integer) :: iodata
  def format(number, illion, _separator, 0), do: [say_io(number) | illion]
  def format(number, illion, separator, remainder), do: [say_io(number), illion, separator | say_io(remainder)]
end
Mike Buhot
  • 4,790
  • 20
  • 31
1

The Cldr library does this (among other things).

Define a module that hosts the configuration for the library:

defmodule MyApp.Cldr do
  use Cldr,
    locales: Application.get_env(:partially, :languages, ["en"]),
    default_locale: "en",
    gettext: MyApp.Gettext,
    providers: [Cldr.Number, Cldr.List]
end

Then you can convert numbers to words like this:

iex> MyApp.Cldr.Number.to_string(103, format: :spellout)
{:ok, "one hundred three"}
iex> MyApp.Cldr.Number.to_string(5765, format: :spellout)
{:ok, "five thousand seven hundred sixty-five"}
Kenny Evitt
  • 9,291
  • 5
  • 65
  • 93