This function computes the English string for any given integer supported by Clojure.
(int->str 110917) ; "one hundred and ten thousand nine hundred and seventeen"
The most important trick used is to first break the number down into its components (i.e. its millions, its thousands, hundreds and ones). We do this by successively dividing the number by the size of each component, starting with the largest supported component and carrying over the remainder. The function solve-components
takes care of this and outputs something of the form:
(solve-components 110927) ;[[:thousand 110] [:hundred 9] [:ten 2] [:one 7]]
Now we can write a function to name each component pair. The function str-of-pair
does this.
(str-of-pair [:thousand 110]) ; "one hundred and ten thousand"
For everything except the :ten
s, :one
s and :teen
s this is just a case of saying (str (int->str value) " " (name component))
. Note the recursion back into int->str
here in order to avoid saying "110 thousand". For the special cases, we use a lookup table.
There is a special case in English, where [:ten 1] [:one 7]
isn't "ten seven" but is rather "seventeen". We handle this by eliminating the :ten
and the :one
components and replacing them with a :teen
component (e.g. [:teen 7]
). The string conversion has a lookup table for :teen
. The teenify
function handle the substitution and is performed at the end of solve-components
.
In English, when a number is not a round hundred, we use the conjuction "and" before the remaining number. To handle this, we rebuild our list of components in reverse. If we see a :hundred
and we've already processed something before it, we inject the [:str "and"]
component, otherwise we just copy as-is. Remember we're processing in reverse to simplify the need to lookahead. The function andify
does this substitution and is performed at the end of solve-components
. Our str-of-pair
treats :str
components as verbatim pieces of text.