I have extensively reviewed 2 old articles on the subject: https://stackoverflow.com/questions/14766951/convert-digits-into-words-with-javascript and https://stackoverflow.com/questions/5529934/javascript-numbers-to-words and the answers therein using various methods for spelling a number into words in English.
I have tried to come-up with new different and simple method I am calling it a Single Loop String Triplets (SLST) and thus avoid the use of excessive arithmetic number operations, switches, array manipulations, reversing or splitting strings/arrays, or function recursion.
The method is not limited to JavaScript and can be used in other programming languages as the structure and flow is simple to code.
The principle applied here is to follow the human reading logic of pronouncing and writing the number (in US English) from Left to Right using the standard US English (i.e. without an “and” after the hundred parts).
The function is made to work for whole numbers (integers). But may be called twice for whole and fractional parts after a number split at the decimal point.
Also currency and sub-currency words could be added easily if a whole/fractional split is made.
It is not intended for the function to do everything or check everything as this could be left to a another higher function that will call this function, therefore the following are not accounted for simplicity:
- No checks for negative numbers.
- No checks for non-number (NaN) strings/data.
- No checks or conversion for exponential notations.
However, large numbers can be passed as a String if necessary.
The “Scale” Array may be increased by adding additional scales above “Decillion”.
It is simple to add a Comma "," after each scale words (except last) as some would prefer that.
Here how it works with an example:
Example Number: 1223000789
One Billion Two Hundred Twenty-Three Million Seven Hundred Eighty-Nine.
1. Stringfy and convert to shortest triplets padded with zero:
NumIn = "0".repeat(NumIn.length * 2 % 3) + NumIn;
The stringfied Number in Triplets is now (2 zeros added to the LH):
001223000789
In other words the number is now:
In our example, no triplets exist for scales above Billions, so no Trillions or above num scales.
2. Get count of Triplets: in this case 4 Triplets (i.e. count 3 to 0):
Triplets = NumIn.length / 3 - 1
3. Loop starting from the Most Significant Triplet (MST) (i.e. like you read the number) and:
(a) Convert each Triplet number to words (1 to 999) and add the scale name after it.
(b) If a triplet is empty (i.e. 000) then skip it.
(c) Join the new Triplet words to the end of the previous one.
Line 7 of the code ensures a hyphen is inserted for numbers between 21 to 99 in accordance with English numerals writing (i.e. Twenty-One, Fifty-Seven, etc.). You could delete that if it does not apply to you together with the associated variable declaration.
Graphical Example of the above:
Result:
One Billion Two Hundred Twenty-Three Million Seven Hundred Eighty-Nine.
I have found this to be the simplest method to understand and code.
I have also coded the same function in VBA.
I would like the code to be reviewed for any bugs, optimization, or improvements. I am sure there is room for improvements and corrections.
Thanks in advance to all, your valuable inputs and feedback appreciated.
Mohsen Alyafei
function NumToWordsInt(NumIn) {
//-------------------------------------------------------
//Convert Integer Number to English Words
//Using a Single Loop String Triplets (SLST) Methods
//Mohsen Alyafei 10 July 2019
//Call it for a whole number and fractional separately
//-------------------------------------------------------
if (NumIn==0) return "Zero";
var Ones = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"];
var Tens = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"];
var Scale = ["", "Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion", "Sextillion", "Septillion", "Octillion", "Nonillion", "Decillion"];
var N1, N2, Sep, L, j, i, h,Trplt,tns="", NumAll = "";
NumIn += ""; //NumIn=NumIn.toString()
//----------------- code start -------------------
NumIn = "0".repeat(NumIn.length * 2 % 3) + NumIn; //Create shortest string triplets 0 padded
j = 0; //Start with the highest triplet from LH
for (i = NumIn.length / 3 - 1; i >= 0; i--) { //Loop thru number of triplets from LH most
Trplt = NumIn.substring(j, j + 3); //Get a triplet number starting from LH
if (Trplt != "000") { //Skip empty triplets
h = ""; //Init hundreds //-------inner code for 1 triplet
Trplt[2] != "0" ? Sep="-":Sep=" "; //Only if hyphen needed for nums 21 to 99
N1 = Number(Trplt[0]); //Get Hundreds digit
N2 = Number(Trplt.substr(1)); //Get 2 lowest digits (00 to 99)
N2 > 19 ? tns = Tens[Number(Trplt[1])] + Sep + Ones[Number(Trplt[2])]:tns = Ones[N2]
if (N1 > 0) h = Ones[N1] + " Hundred" //Add " hundred" if needed
Trplt = (h + " " + tns).trim() + " " + Scale[i]; //Create number with scale ----inner code ends
NumAll = NumAll + Trplt + " "; //join the triplets scales to previous
}
j += 3; //Go for next lower triplets (move to RH)
}
//----------------- code end ---------------------
return NumAll.trim(); //Return trimming excess spaces
}
//
//
//================= for testing ================
document.getElementById('number').onkeyup = function () {
document.getElementById('words').innerHTML = NumToWordsInt(document.getElementById('number').value);
};
<span id="words"></span>
<input id="number" type="text" />