3
\$\begingroup\$

I have developed the following short JavaScript function to convert numbers to the Indian Numbering System formats; both the Official Numbering System and the Common-Use System (i.e. using the Lakh-Crore System) using the method of converting the number into strings of Siptlets and Duplets.

Based on this wiki article that explains the Indian Numbering System I have created the following summary table that translates the same into a steps/flow logic that can then be translated into appropriate code.

enter image description here

So, based on the above (and my understanding of the subject), I have worked out the JavaScript function below to handle:

  1. The Official Numbering System, and
  2. The Common-Use Numbering System, and
  3. If needed Indian Currency.

I have tried to (as far as possible) use ES6 keywords and functions.

When generating the Common-Use text, a "comma" is inserted between each Siptlet text as the output is long and difficult to follow. However, this comma can be deleted on the 8th line of the code if not desired.

I have also included 2 test case codes to test both Numbering Systems.

The function can be called for the Common-Use as follows:

Numbers to be converted can be passed as Numbers or Strings.

integerToWordsInd("2222300000"));       // Two hundred Twenty-Two Crore, Twenty-Three Lakh

and for the Official System:

integerToWordsInd ("2222300000",true);  // Two Arab Twenty-Two Crore Twenty-Three Lakh

An additional function numberCurrencyInd() is also added to convert the number into Indian Currency "Rupees and Paisa", and may use the Official or Common-Use System as an option using the calling parameters (similar to the number conversion function).

It also serves as an example of how to call the function for the whole part of numbers and fractional parts of the number.

numberCurrencyIn(3002900000.50);         //Three Hundred Crore, Twenty-Nine Lakh Rupees and Fifty Paisa

// or

numberCurrencyIn(3002900000.50,true);    // Three Arab Twenty-Nine Lakh Rupees and Fifty Paisa

Two (2) further rest cases are added to test currency generation under both Systems.

Some internals workings of the functions are:

The following line converts the number into array elements of Siptlets (7s) (fixed size 7 digits) for use in the Common-Use Numbering System:

Num = ("0".repeat(6*(Num+="").length % 7) +Num).match(/.{7}/g);

The following line converts the number into array elements of 1 Triplet followed by Duplets for use in both the Official and Common-Use Numbering System:

Num = Num> 999 ? [...(Num.slice(0,-3).match(/.{2}/g).map(e => "0"+e)),(Num.slice(-3))] :
                  [("00"+Num).substr(-3)];

If the Common-Use System is requested, then the number is first converted into Siptlets (7's) then the inner function is called for each Siptlet to generate the words using the Triplet/Duplets.

However, if instead, the Official System is requested then the inner function is called immediately to generate the words using the Triplet/Duplets.

/*********************************************************************
* @function    : integerToWordsInd()
* @purpose     : Converts Unsigned Integers to Indian Numeral Words
*                With options for either the Official or the
*                Crore-Lakh Counting Systems
* @version     : 1.00
* @author      : Mohsen Alyafei
* @date        : 07 July 2020
* @param       : {number} [integer numeric or string]
* @param       : Optional {boolean} [Official]
*                      0     = Use Crore-Lakh Counting System (default)
*                      Non 0 = Use the Official System
* @returns     : {string} The wordified number string
**********************************************************************/
var Table_0_19 = ["","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"],
    Table_20_90= ["","","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"],
    Table_Scale= ["","Thousand","Lakh","Crore","Arab","Kharab","Neel","Padma","Shankh","Samudra","Antya","Madhyam","Paraardh","***","***"];
//===================================================================
function integerToWordsInd(Num=0 , Official=0) {
if (Num===0) return "Zero";
if (Official) return Siptlets(Num);                   // Return Official Numbering System text
let NumWords="";
Num = ("0".repeat(6*(Num+="").length % 7) +Num).match(/.{7}/g); // Create Siptlets Array
return Num.map((Siptlet, ScalePos) => {               // Return Commmon-Use Numbering System text
  let [Scale,SWords] = [(Table_Scale[3]+" ").repeat(Num.length-ScalePos-1).trimRight(), Siptlets(Siptlet)];
  NumWords +=(NumWords && SWords ? ", " : "") +SWords +(Scale ? " " : "") +Scale;
}), NumWords;
//===================================================================
function Siptlets(Num, NumWords="") {                 // Core function (Called for both Systems)
(Num+="").length-3 & 1 && (Num="0"+Num);
Num = Num> 999 ? [...Num.slice(0,-3).match(/.{2}/g).map(e => "0"+e),(Num.slice(-3))]:[("00"+Num).substr(-3)];
return Num.map((Duplet,ScalePos) => {if (+Duplet) {
let [Hyphen,Hundreds,Tens,Scale] = [+Duplet[2] ? "-" : "",+Duplet[0],+Duplet.substr(1),Table_Scale[Num.length-ScalePos-1]];
NumWords  += (NumWords          ? " " : "") + (Hundreds ? Table_0_19[Hundreds] + " Hundred" :"") +
             (Hundreds && Tens  ? " " : "") + (Tens< 20 ? Table_0_19[Tens] :
             Table_20_90[+(Duplet[1])]      + Hyphen    + Table_0_19[+Duplet[2]]);
NumWords  += (NumWords && Scale ? " " : "") + Scale;
}}), NumWords;}
}
//===================================================================




//===================================================================
//      Extra Function if needed for Indian Currency
// Uses same input parameters as the above main function
//===================================================================
function numberCurrencyIn(Num=0 , Official=0) {
let n= (Num+"").split(0.1.toLocaleString().substr(1,1)); // Number and Fraction parts
n.length!==2 && (n[1]= ""); // No fraction
Num= n[0];
let Nw="", Fw="", Frc = (n[1]+"00").substring(0,2); // Limit to 2 Decimal Places
Num && (Nw= integerToWordsInd(Num,Official));       // Convert the Whole Number
Frc && (Fw= integerToWordsInd(Frc,Official));       // Convert the Fractional Part
return (Nw ? Nw:"") + (Nw ? " Rupees":"") + (Nw && Fw ? " and ":"") + (Fw ? Fw+" Paisa":""); // Join together
}
//===================================================================



//===================================================================
//                     Test Cases
//===================================================================
// 1. Test Numbers under Common-Use Numbering System
//===================================================================
var r=0; // test tracker
r |= testN(50,"Fifty");
r |= testN(12000,"Twelve Thousand");
r |= testN(777000,"Seven Lakh Seventy-Seven Thousand");
r |= testN(550001,"Five Lakh Fifty Thousand One");
r |= testN(12345678,"One Crore, Twenty-Three Lakh Forty-Five Thousand Six Hundred Seventy-Eight");
r |= testN(123456789,"Twelve Crore, Thirty-Four Lakh Fifty-Six Thousand Seven Hundred Eighty-Nine");
r |= testN(1234567890,"One Hundred Twenty-Three Crore, Forty-Five Lakh Sixty-Seven Thousand Eight Hundred Ninety");
r |= testN(12345678900,"One Thousand Two Hundred Thirty-Four Crore, Fifty-Six Lakh Seventy-Eight Thousand Nine Hundred");
if (r==0) console.log("Test Case 1 Numbers (Common-Use Numbering System) Passed.");
//===================================================================
// 2. Test Numbers under Official Numbering System
//===================================================================
var r=0; // test tracker
r |= testN(50,"Fifty");
r |= testN(12000,"Twelve Thousand",true);
r |= testN(777000,"Seven Lakh Seventy-Seven Thousand",true);
r |= testN(550001,"Five Lakh Fifty Thousand One",true);
r |= testN(12345678,"One Crore Twenty-Three Lakh Forty-Five Thousand Six Hundred Seventy-Eight",true);
r |= testN(123456789,"Twelve Crore Thirty-Four Lakh Fifty-Six Thousand Seven Hundred Eighty-Nine",true);
r |= testN(1234567890,"One Arab Twenty-Three Crore Forty-Five Lakh Sixty-Seven Thousand Eight Hundred Ninety",true);
r |= testN(12345678900,"Twelve Arab Thirty-Four Crore Fifty-Six Lakh Seventy-Eight Thousand Nine Hundred",true);
if (r==0) console.log("Test Case 2 Numbers (Official Numbering System) Passed.");
//===================================================================
// 3. Test Currency under Common-Use Numbering System
//===================================================================
var r=0; // test tracker
r |= testC(1,"One Rupees");
r |= testC(2.0,"Two Rupees");
r |= testC(2.01,"Two Rupees and One Paisa");
r |= testC(0.3,"Thirty Paisa");
r |= testC(.3,"Thirty Paisa");
r |= testC(3002900000.50,"Three Hundred Crore, Twenty-Nine Lakh Rupees and Fifty Paisa");
r |= testC(220000,"Two Lakh Twenty Thousand Rupees");
if (r==0) console.log("Test Case 3 Currency (Common-Use Numbering System) Passed.");
//===================================================================
// 4. Test Currency under Official Numbering System
//===================================================================
var r=0; // test tracker
r |= testC(3002900000.50,"Three Arab Twenty-Nine Lakh Rupees and Fifty Paisa",true);
r |= testC(55000000000,"Fifty-Five Arab Rupees",true);
if (r==0) console.log("Test Case 4 Currency (Official Numbering System) Passed.");
//===================================================================
function testN(n,tobe,f) {let r = integerToWordsInd(n,f);
if (r !== tobe) {console.log(`${n} Output   : ${r}\n${n} Should be: ${tobe}`);return 1;}}
function testC(n,tobe,f) {let r = numberCurrencyIn(n,f);
if (r !== tobe) {console.log(`${n} Output   : ${r}\n${n} Should be: ${tobe}`);return 1;}}

\$\endgroup\$
1
\$\begingroup\$

Ok, I need to be honest here: This code is atrocious. You are virtually breaking every rule in the book. And considering the work you put into the introduction, I have to assume you do it on purpose. My general advice would be: Put the effort you do into your code and then you'll won't need to write so much documentation.

I won't even go into the formatting issues, because I'd have to copy and paste a complete style guide here. Go out and read some of the existing style guides and apply them to your code. Or if that is too much work, install and use a code formatter in your editor/IDE/build tools.

If you want to optimize code execution use a minifier for the production code, but don't use syntax just to write as little code/as few lines as possible, such as:

  • Don't use of the comma operator. At all. Especially not in the return expression like you are. Why don't just place the map before the return? (BTW, you are misusing map here. It should be a forEach or a reduce instead.)
  • Don't misuse deconstrution assignments just to press as much code as possible into one line.
  • Don't use && as a replacement for if.
  • Don't reuse variables, such as the Num parameter.

“Programs are meant to be read by humans and only incidentally for computers to execute.”

― Donald Knuth

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the useful and good feedback. Some old habits never die :-). \$\endgroup\$ Aug 2 '20 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.