# How to express an integer number in English words?

How do I convert a number to a readable string?

I would like to implement a function, inWords[],

    inWords[n_]:= ?


which should return a readable English string.

A few expected results:

inWords[123456]
" one hundred twenty three thousand four hundred fifty six"

inWords[1000000001]
"one billion one"

inWords[123456789123456789]

"one hundred twenty three quadrillion four hundred fifty six trillion \
seven hundred eighty nine billion one hundred twenty three million \
four hundred fifty six thousand seven hundred eighty nine"


On the other hand, how do I implement a function to do exactly the reverse of this? That is, to read and parse string and convert the string to a number?

Note The Stack Overflow post Express a number using words in Mathematica tries to answers second part of my question.

However, it uses WolframAlpha which expects one to be connected to the Internet, and there are restrictions on number of calls made so, a non-WolframAlpha answer would be much nicer.

• Is it possible to convert Speak into text? If so that seems like something to try. (SpokenString just returns the number) Jan 31, 2012 at 22:06
• I thought about it but if a number grows larger it reads it out using scientific notation !! Jan 31, 2012 at 22:09
• Yes it does! never tried that before Jan 31, 2012 at 22:12
• Maybe you'll like this little thing I made a couple of years ago: 99-bottles-of-beer.net/language-mathematica-1712.html Jan 31, 2012 at 23:13
• You might want some localisation in there, UK-GB say 'one hundred and twenty six thousand' Feb 1, 2012 at 14:35

Nested WolframAlpha approach, showing the intermediate steps:

numberString[a_, k_: 10] :=
FixedPointList[
StringReplace[#,
b : (DigitCharacter ..) :>
WolframAlpha["spell " <> b, {{"Result", 1}, "Plaintext"}]] &, a,
k]

numberString["123456"]

(*
==> {"123456", "123 thousand and 456", "one hundred twenty-three \
thousand and four hundred fifty-six", "one hundred twenty-three \
thousand and four hundred fifty-six"}
*)

numberString["123456789123456789123456789"]

(*
==> {"123456789123456789123456789", "123 septillion, 456 \
sextillion, 789 quintillion, 123 quadrillion, 456 trillion, 789 \
billion, 123 million, 456 thousand and 789", "one hundred \
twenty-three septillion, four hundred fifty-six sextillion, seven \
hundred eighty-nine quintillion, one hundred twenty-three \
quadrillion, four hundred fifty-six trillion, seven hundred \
eighty-nine billion, one hundred twenty-three million, four hundred \
fifty-six thousand and seven hundred eighty-nine", "one hundred \
twenty-three septillion, four hundred fifty-six sextillion, seven \
hundred eighty-nine quintillion, one hundred twenty-three \
quadrillion, four hundred fifty-six trillion, seven hundred \
eighty-nine billion, one hundred twenty-three million, four hundred \
fifty-six thousand and seven hundred eighty-nine"}
*)

• can SpokenString be made to return the written/textual version of a number if given a number as an argument? It doesn't appear to to that but can you ask someone about that? Jan 31, 2012 at 22:43

Mathematica 10 introduces IntegerName:

• IntegerName[n] gives a string containing the full English name of the integer n.

• IntegerName[n,"type"] gives a string of the specified type.

Possible types include:

• "DigitsWords" a combination of three-digit numbers and words
• "Words" using only words
• "Approximate" the first few digits plus thousands, millions, etc.
• "ApproximateWords" the first few digits as words plus thousands, etc.

Example:

IntegerName[#, "Words"] & /@
{123456, 1000000001, 123456789123456789} // Column

"one hundred twenty-three thousand, four hundred fifty-six"

"one billion, one"

"one hundred twenty-three quadrillion, four hundred fifty-six trillion,
seven hundred eighty-nine billion, one hundred twenty-three million,
four hundred fifty-six thousand, seven hundred eighty-nine"


Messy but a working method

inWords[n_] := Module[
{r,
numNames = {"", " one", " two", " three", " four", " five",
" six", " seven", " eight", " nine"},
teenNames = {" ten", " eleven", " twelve", " thirteen",
" fourteen", " fifteen", " sixteen", " seventeen", " eighteen",
" nineteen"},
tensNames = {"", " ten", " twenty", " thirty", " forty", " fifty",
" sixty", " seventy", " eighty", " ninety"},
decimals = {"", " thousand", " million", " billion", " trillion",
" quadrillion", " quintillion", " sextillion", " septillion",
" octillion", " nonillion", " decillion", " undecillion",
" duodecillion", " tredecillion", " quattuordecillion",
" quindecillion", " sexdecillion", " septendecillion",
" octodecillion", " Novemdecillion", " Vigintillion", " 66illion",
" 69illion"}

}
,
r = If[# != 0,
numNames[[# + 1]] <> " hundred" <>
If[#2 != 0 || #3 != 0, " and", ""], ""]
<>
Switch[#2
, 0, numNames[[#3 + 1]]
, 1, teenNames[[#3 + 1]]
, _, tensNames[[#2 + 1]] <> numNames[[#3 + 1]]
]
& @@@
3] & /@ StringCases[StringReverse@IntegerString@n,
RegularExpression["\\d{1,3}"]]);

StringJoin@
Reverse@
If[# != "", StringJoin[##], ""] &, {r, Take[decimals, Length@r]}]
];


Output

In[279]:= FromDigits@Table[RandomInteger[9], {70}]
inWords@%

Out[279]= \
7317782180245641104170634561625559007936487060051082174021876603737988

Out[280]= " seven 69illion three hundred and seventeen 66illion seven \
hundred and eighty two Vigintillion one hundred and eighty \
Novemdecillion two hundred and forty five octodecillion six hundred \
and forty one septendecillion one hundred and four sexdecillion one \
hundred and seventy quindecillion six hundred and thirty four \
quattuordecillion five hundred and sixty one tredecillion six hundred \
and twenty five duodecillion five hundred and fifty nine undecillion \
seven decillion nine hundred and thirty six nonillion four hundred \
and eighty seven octillion sixty septillion fifty one sextillion \
eighty two quintillion one hundred and seventy four quadrillion \
twenty one trillion eight hundred and seventy six billion six hundred \
and three million seven hundred and thirty seven thousand nine \
hundred and eighty eight"

• My only objection, at least in American standard English, the "and" is used to refer to the existence of a decimal fraction, e.g. $1.8$ is "one and eight tenths". But, it is not used in numbers without fractional parts, e.g. $185$ is "one hundred eighty five." Additionally, the "and" is used inconsistently in your code it shows up for $1295$, but not for $1095$. Feb 1, 2012 at 1:52
• The 'and' should be used for things like 123 =>one hundred and twenty three. It's used in the wrong places above. Also, it shouldn't use the American method, generally, because the American method uses an incomplete and truncated counting system. 1,000,000,000 is 1 thousand million, not 1 billion, which makes using the American system deliver incorrect output at large values. The shorthand is a convenient, but not accurate, counting system. Feb 1, 2012 at 8:05

In Mathematica 8 you can use free form input :

= Spell 15


and you get

"fifteen"


Or just write

= thirty


and you obtain

30


Since for larger numbers this approach yields expressions like {number words number, _ } one could nest this arbitrarily to obtain expressions containing only words. In fact, it is sufficient to nest only two times. For example :

words[x_] :=
Nest[StringReplace[#,
n : (DigitCharacter ..)  :>
WolframAlpha["spell " <> n,
{{"Result", 1}, "Plaintext"}]
] &,  ToString @ x, 2]
words[8936546956]
(*
==>  "eight billion, nine hundred thirty-six million, five
hundred forty-six thousand and nine hundred fifty-six"
*)


On the other hand, writing :

 =   eight billion, nine hundred thirty-six million, five
hundred forty-six thousand and nine hundred fifty-six
(*
==>  8936546956
*)

• This doesn't work for larger numbers. Try for 123456 and it returns "123 thousand and 456"
– rm -rf
Jan 31, 2012 at 22:21
• Apply recursively... Jan 31, 2012 at 22:25
• @brett it gets complicated pretty fast. You have to devise a stopping criterion etc. Jan 31, 2012 at 22:27
num = 1234567891234567899;
triples =
Reverse /@ Reverse@Partition[Reverse@IntegerDigits[num], 3, 3, 1, 0];

threePowers = {"septillion", "sextillion", "quintillion",
"quadrillion", "trillion", "billion", "million", "thousand", ""};
singleRules = {0 -> "", 1 -> "one", 2 -> "two", 3 -> "three",
4 -> "four", 5 -> "five", 6 -> "six", 7 -> "seven", 8 -> "eight",
9 -> "nine"};
tenRules = {0 -> "ten", 1 -> "eleven", 2 -> "twelve", 3 -> "thirteen",
4 -> "fourteen", 5 -> "fifteen", 6 -> "sixteen", 7 -> "seventeen",
8 -> "eighteen", 9 -> "nineteen"};
decadeRules = {1 -> "ten", 2 -> "twenty", 3 -> "thirty",
4 -> "fourty", 5 -> "fifty", 6 -> "sixty", 7 -> "seventy",
8 -> "eighty", 9 -> "ninety"};

rules =
{
{0, 0, 0} :> "",
{0, 0, s_ /; s > 0} :> ToString[s /. singleRules],
{0, 1, s_} :> ToString[s /. tenRules],
{0, t_ /; t > 1, s_} :>
ToString[t /. decadeRules] <> " " <> ToString[s /. singleRules],
{h_, 0, 0} :> ToString[h /. singleRules] <> " hundred",
{h_, 0, s_ /; s > 0} :>
ToString[h /. singleRules] <> " hundred and " <>
ToString[s /. singleRules],
{h_, 1, s_} :>
ToString[h /. singleRules] <> " hundred and " <>
ToString[s /. tenRules],
{h_, t_ /; t > 1, s_} :>
ToString[h /. singleRules] <> " hundred and " <>
ToString[t /. decadeRules] <> " " <> ToString[s /. singleRules]
};

ToString[#1 /. rules] <> " " <> ToString[#2] <> " " &, {triples,
Take[threePowers, -Length[triples]]}] // StringJoin

(*
==> "one quintillion two hundred and thirty four quadrillion \
five hundred and sixty seven trillion eight hundred and ninety one \
billion two hundred and thirty four million five hundred and sixty \
seven thousand eight hundred and ninety nine  "
*)

• At least in American standard English, "and" is used to refer to the decimal point in a fractional number, e.g. $1.8$ is "one and eight tenths", and not used any where else, e.g. $185$ is "one hundred eighty five." Besides its use is inconsistent in the same manner as this answer. Feb 1, 2012 at 1:56
• @rcollyer I'm mostly using British English as that's what I was taught at school and in British English 'and' is normal (en.wikipedia.org/wiki/English_numerals). Feb 1, 2012 at 13:18

This solution is similar in spirit to Prashant's. Though not particularly elegant, I avoid any calls to W|A and any other form of internet connectivity. Further down the post I also provide a solution to the inverse problem of returning the number when given English words.

numberform[n_]:=With[{id=IntegerDigits@n},

single={"One","Two","Three","Four","Five","Six","Seven","Eight","Nine"};
teen=  {"Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen",
"Sixteen","Seventeen","Eighteen","Nineteen"};
double={"Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
"Quintillion","Sextillion","Septillion","Octillion","Nonillion",
"Decillion","Undecillion","Duodecillion","Tredecillion",
"Quattuordecillion","Quindecillion","Sexdecillion",
"Septendecillion","Octodecillion","Novemdecillion","Vigintillion"};

tens[t_,o_]:=
If[o==0,""," "<>ones[o]]]

hundreds[arg:{h_,t_,o_}]:=
Switch[arg,{0,0,0},"",{0,0,_},ones[o],{0,_,_},tens[t,o],_,ones[h]<>
" Hundred "<>tens[t,o]]

createBlock[b_,n_]:=If[MatchQ[b,""],"",b<>" "<>
Switch[n,1,"",x_/;x<=22,big[[n-1]]<>
" ",_,ToString[3 (n-1)]<>"-illion "]]

inWords[h_]:=If[h==0,"Zero",With[{n=numberform[h]},
StringJoin@@Table[createBlock[hundreds@n[[i]],Length[n]-i+1]
,{i,Length[n]}]]]


Here is the example Prashant gave...

In[55]:=
inWords[7317782180245641104170634561625559007936487060051082174021876603737988]

Out[55]= "Seven 69-illion Three Hundred Seventeen 66-illion Seven Hundred
Eighty Two Vigintillion One Hundred Eighty Novemdecillion Two Hundred
Forty Five Octodecillion Six Hundred Forty One Septendecillion One
Hundred Four Sexdecillion One Hundred Seventy Quindecillion Six
Hundred Thirty Four Quattuordecillion Five Hundred Sixty One
Tredecillion Six Hundred Twenty Five Duodecillion Five Hundred Fifty
Nine Undecillion Seven Decillion Nine Hundred Thirty Six Nonillion
Four Hundred Eighty Seven Octillion Sixty Septillion Fifty One
Sextillion Eighty Two Quintillion One Hundred Seventy Four
Quadrillion Twenty One Trillion Eight Hundred Seventy Six Billion Six
Hundred Three Million Seven Hundred Thirty Seven Thousand Nine
Hundred Eighty Eight"


Now to answer part 2 we need to work do the inverse of inWords.

tonum[args___,last_]/;StringMatchQ[last,Alternatives@@big|"*illion"]:=
blockNum[last]*hundredNum[args]
tonum[args___,last_]:= hundredNum[args,last]
tonum[]:= 0

blockNum[arg:Alternatives@@big]:= 10^(3 Position[big,arg][[1,1]])
blockNum[bigNum_]:=
Power[10,Sequence@@ToExpression[StringCases[bigNum,DigitCharacter..]]]

teenNum[]:= 0;
teenNum[t_,o_]:= tenNum[t,o]
Join[Range[20,90,10],{oneNum[t]}]]]
tenNum[t_,o_]:= tenNum[t]+oneNum[o]
hundredNum[h_,"Hundred",t___]:= 100*oneNum[h]+teenNum[t]
hundredNum[h___]:= teenNum[h]

inNumbers[n_]:= Block[{temp=StringSplit[n],split,spans,parts},
split=Pick[Range[Length[temp]],
(MemberQ[big,#]||StringMatchQ[#,"*illion"])&/@temp
];
spans=Span@@@Transpose[{Join[{1},split+1],Join[split,{Length[temp]}]}];
parts=temp[[#]]&/@spans;
Total[tonum@@@parts]
]


So inNumbers should be able to take a string version of the number and return the digits...

In[51]:= n =
7317782180245641104170634561625559007936487060051082174021876603737988;

In[52]:= inNumbers@inWords[n] == n

Out[52]= True


I used the following to solve Problem 17 from Project Euler (hint hint). It's working on numbers up to 1000, but the grammar of larger numbers is trivial compared to small numbers and should easily be able to be implemented.

Usage:

numberToWord /@ {14, 271, 944}

{"fourteen", "two hundred and seventy-one", "nine hundred and forty-four"}


Source:

numberToWord[n_]:=Module[{result,digits},
result=ConstantArray["",3]; (* {thousand, hundred, <100} *)
If[n>=1000,result[[1]]=numberToWord[Quotient[n,1000]]<>" thousand"];
(* Mod[Quotient[n,100],10] extracts the 100s-digit *)
If[n>=100\[And]Mod[Quotient[n,100],10]!=0,
result[[2]]=numberToWord[Mod[Quotient[n,100],10]]<>" hundred";
If[Mod[n,100]!=0,result[[2]]=result[[2]]<>" and"];
];
digits=Mod[n,100];
result[[3]]=Which[
digits==0,"",
digits==1,"one",
digits==2,"two",
digits==3,"three",
digits==4,"four",
digits==5,"five",
digits==6,"six",
digits==7,"seven",
digits==8,"eight",
digits==9,"nine",
digits==10,"ten",
digits==11,"eleven",
digits==12,"twelve",
digits==13,"thirteen",
digits==14,"fourteen",
digits==15,"fifteen",
digits==16,"sixteen",
digits==17,"seventeen",
digits==18,"eighteen",
digits==19,"nineteen",
20<=digits<=29,"twenty",
30<=digits<=39,"thirty",
40<=digits<=49,"forty",
50<=digits<=59,"fifty",
60<=digits<=69,"sixty",
70<=digits<=79,"seventy",
80<=digits<=89,"eighty",
90<=digits<=99,"ninety"
];
If[Mod[n,100]>20\[And]Mod[n,10]!=0,result[[3]]=result[[3]]<>"-"<>numberToWord[Mod[n,10]]];

(* Join the words spaced *)
StringJoin[result//Select[#,#!=""&]&//Riffle[#," "]&]
]