Add commas or spaces to group every three digits

JavascriptString Formatting

Javascript Problem Overview


I have a function to add commas to numbers:

function commafy( num ) {
  num.toString().replace( /\B(?=(?:\d{3})+)$/g, "," );
}

Unfortunately, it doesn't like decimals very well. Given the following usage examples, what is the best way to extend my function?

commafy( "123" )                 // "123"
commafy( "1234" )                // "1234"
                                 // Don't add commas until 5 integer digits
commafy( "12345" )               // "12,345"
commafy( "1234567" )             // "1,234,567"
commafy( "12345.2" )             // "12,345.2"
commafy( "12345.6789" )          // "12,345.6789"
                                 // Again, nothing until 5
commafy( ".123456" )             // ".123 456"
                                 // Group with spaces (no leading digit)
commafy( "12345.6789012345678" ) // "12,345.678 901 234 567 8"

Presumably the easiest way is to first split on the decimal point (if there is one). Where best to go from there?

Javascript Solutions


Solution 1 - Javascript

Just split into two parts with '.' and format them individually.

function commafy( num ) {
    var str = num.toString().split('.');
    if (str[0].length >= 5) {
        str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,');
    }
    if (str[1] && str[1].length >= 5) {
        str[1] = str[1].replace(/(\d{3})/g, '$1 ');
    }
    return str.join('.');
}

Solution 2 - Javascript

Simple as that:

var theNumber = 3500;
theNumber.toLocaleString();

Solution 3 - Javascript

Here are two concise ways I think maybe useful:

  1. Number.prototype.toLocaleString

This method can convert a number to a string with a language-sensitive representation. It allows two parameters, which is locales & options. Those parameters may be a bit confusing, for more detail see that doc from MDN above.

In a word, you could simply use is as below:

console.log(
   Number(1234567890.12).toLocaleString()
)
// log -> "1,234,567,890.12"

If you see different with me that because we ignore both two parameters and it will return a string base on your operation system.

  1. Use regex to match a string then replace to a new string. > Why we consider this? The toLocaleString() is a bit confusing and not all browser supported, also toLocaleString() will round the decimal, so we can do it in another way.
// The steps we follow are:
// 1. Converts a number(integer) to a string.
// 2. Reverses the string.
// 3. Replace the reversed string to a new string with the Regex
// 4. Reverses the new string to get what we want.

// This method is use to reverse a string.
function reverseString(str) { 
    return str.split("").reverse().join("");  
}

/**
 * @param {string | number} 
 */
function groupDigital(num) {
  const emptyStr = '';
  const group_regex = /\d{3}/g;

  // delete extra comma by regex replace.
  const trimComma = str => str.replace(/^[,]+|[,]+$/g, emptyStr)


  const str = num + emptyStr;
  const [integer, decimal] = str.split('.')

  const conversed = reverseString(integer);

  const grouped = trimComma(reverseString(
    conversed.replace(/\d{3}/g, match => `${match},`)
  ));
  
  return !decimal ? grouped : `${grouped}.${decimal}`;
}


console.log(groupDigital(1234567890.1234)) // 1,234,567,890.1234
console.log(groupDigital(123456))  // 123,456
console.log(groupDigital("12.000000001"))  // 12.000000001

Solution 4 - Javascript

Easiest way:

#1

var num = 1234567890,
result = num.toLocaleString() ;// result will equal to "1 234 567 890"

#2

var num = 1234567.890,
result = num.toLocaleString() + num.toString().slice(num.toString().indexOf('.')) // will equal to 1 234 567.890

#3

var num = 1234567.890123,
result = Number(num.toFixed(0)).toLocaleString() + '.' + Number(num.toString().slice(num.toString().indexOf('.')+1)).toLocaleString()
//will equal to 1 234 567.890 123

#4 If you want ',' instead of ' ':

var num = 1234567.890123,
result = Number(num.toFixed(0)).toLocaleString().split(/\s/).join(',') + '.' + Number(num.toString().slice(num.toString().indexOf('.')+1)).toLocaleString()
//will equal to 1,234,567.890 123

If not working, set the parameter like: "toLocaleString('ru-RU')" parameter "en-EN", will split number by the ',' instead of ' '

All function used in my code are native JS functions. You'll find them in GOOGLE or in any JS Tutorial/Book

Solution 5 - Javascript

If you are happy with the integer part (I haven't looked at it closly), then:

function formatDecimal(n) {
  n = n.split('.');
  return commafy(n[0]) + '.' + n[1];
}

Of course you may want to do some testing of n first to make sure it's ok, but that's the logic of it.

Edit

Ooops! missed the bit about spaces! You can use the same regular exprssion as commafy except with spaces instead of commas, then reverse the result.

Here's a function based on vol7ron's and not using reverse:

function formatNum(n) {
  var n = ('' + n).split('.');
  var num = n[0];
  var dec = n[1];
  var r, s, t;
  
  if (num.length > 3) {
    s = num.length % 3;
    
    if (s) {
      t = num.substring(0,s);
      num = t + num.substring(s).replace(/(\d{3})/g, ",$1");
    } else {
      num = num.substring(s).replace(/(\d{3})/g, ",$1").substring(1);
    }
  }
  
  if (dec && dec.length > 3) {
    dec = dec.replace(/(\d{3})/g, "$1 ");
  }

  return num + (dec? '.' + dec : '');
}

Solution 6 - Javascript

I have extended #RobG's answer a bit more and made a sample jsfiddle

function formatNum(n, prec, currSign) {
    if(prec==null) prec=2;
  var n = ('' + parseFloat(n).toFixed(prec).toString()).split('.');
  var num = n[0];
  var dec = n[1];
  var r, s, t;

  if (num.length > 3) {
    s = num.length % 3;

    if (s) {
      t = num.substring(0,s);
      num = t + num.substring(s).replace(/(\d{3})/g, ",$1");
    } else {
      num = num.substring(s).replace(/(\d{3})/g, ",$1").substring(1);
    }
  }
    return (currSign == null ? "": currSign +" ") + num + (dec? '.' + dec : '');
}
alert(formatNum(123545.3434));
alert(formatNum(123545.3434,2));
alert(formatNum(123545.3434,2,'€'));

and extended same way the #Ghostoy's answer

function commafy( num, prec, currSign ) {
    if(prec==null) prec=2;
    var str = parseFloat(num).toFixed(prec).toString().split('.');
    if (str[0].length >= 5) {
        str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,');
    }
    if (str[1] && str[1].length >= 5) {
        str[1] = str[1].replace(/(\d{3})/g, '$1 ');
    }
    return (currSign == null ? "": currSign +" ") + str.join('.');
}

alert(commafy(123545.3434));

Solution 7 - Javascript

Here you go edited after reading your comments.

function commafy( arg ) {
   arg += '';                                         // stringify
   var num = arg.split('.');                          // incase decimals
   if (typeof num[0] !== 'undefined'){
      var int = num[0];                               // integer part
      if (int.length > 4){
         int     = int.split('').reverse().join('');  // reverse
         int     = int.replace(/(\d{3})/g, "$1,");    // add commas
         int     = int.split('').reverse().join('');  // unreverse
      }
   }
   if (typeof num[1] !== 'undefined'){
      var dec = num[1];                               // float part
      if (dec.length > 4){
         dec     = dec.replace(/(\d{3})/g, "$1 ");    // add spaces
      }
   }

   return (typeof num[0] !== 'undefined'?int:'') 
        + (typeof num[1] !== 'undefined'?'.'+dec:'');
}

Solution 8 - Javascript

This worked for me:

function commafy(inVal){
   var arrWhole = inVal.split(".");
   var arrTheNumber = arrWhole[0].split("").reverse();
   var newNum = Array();
   for(var i=0; i<arrTheNumber.length; i++){
          newNum[newNum.length] = ((i%3===2) && (i<arrTheNumber.length-1)) ? "," + arrTheNumber[i]: arrTheNumber[i];
   }
   var returnNum = newNum.reverse().join("");
   if(arrWhole[1]){
          returnNum += "." + arrWhole[1];
   }
   return returnNum;
}

Solution 9 - Javascript

Assuming your usage examples are not representative of already-working code but instead desired behavior, and you are looking for help with the algorithm, I think you are already on the right track with splitting on any decimals.

Once split, apply the existing regex to the left side, a similiar regex adding the spaces instead of commas to the right, and then rejoin the the two into a single string before returning.

Unless, of course, there are other considerations or I have misunderstood your question.

Solution 10 - Javascript

This is basically the same as the solution from Ghostoy, but it fixes an issue where numbers in the thousands are not handled properly. Changed '5' to '4':

export function commafy(num) {
    const str = num.toString().split('.');
    if (str[0].length >= 4) {
        str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,');
    }
    if (str[1] && str[1].length >= 4) {
        str[1] = str[1].replace(/(\d{3})/g, '$1 ');
    }
    return str.join('.');
}

Solution 11 - Javascript

//Code in Java
private static String formatNumber(String myNum) {
    char[] str = myNum.toCharArray();
    int numCommas = str.length / 3;
    char[] formattedStr = new char[str.length + numCommas];

    for(int i = str.length - 1, j = formattedStr.length - 1, cnt = 0; i >= 0 && j >=0 ;) {
        if(cnt != 0 && cnt % 3 == 0 && j > 0) {
            formattedStr[j] = ',';
            j--;
        }

        formattedStr[j] = str[i];
        i--;
        j--;
        cnt++;
    }
    return String.valueOf(formattedStr);
}

Solution 12 - Javascript

You can do it mathematically, depending on how many digits you want to separate, you can start from one digit with 10 to 100 for 2, and so on.

function splitDigits(num) {
    num=Math.ceil(num);
    let newNum = '';
    while (num > 1000){
      let remain = num % 1000;
      num = Math.floor(num / 1000);
      newNum = remain + ',' + newNum;
    }
    return num + ',' + newNum.slice(0,newNum.length-1);
  }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSophie AlpertView Question on Stackoverflow
Solution 1 - JavascriptGhostoyView Answer on Stackoverflow
Solution 2 - JavascriptItay MerchavView Answer on Stackoverflow
Solution 3 - JavascriptTommYView Answer on Stackoverflow
Solution 4 - JavascriptAlexander SoloveyView Answer on Stackoverflow
Solution 5 - JavascriptRobGView Answer on Stackoverflow
Solution 6 - JavascriptHGMamaciView Answer on Stackoverflow
Solution 7 - Javascriptvol7ronView Answer on Stackoverflow
Solution 8 - JavascriptCLaFargeView Answer on Stackoverflow
Solution 9 - JavascriptDan WitkowskiView Answer on Stackoverflow
Solution 10 - JavascriptJyan RensenView Answer on Stackoverflow
Solution 11 - JavascriptManish SinhaView Answer on Stackoverflow
Solution 12 - JavascriptGhazaleh HView Answer on Stackoverflow