How to print a number with commas as thousands separators in JavaScript
Solution 1
I used the idea from Kerry's answer, but simplified it since I was just looking for something simple for my specific purpose. Here is what I have:
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0, "0");
failures += !test(100, "100");
failures += !test(1000, "1,000");
failures += !test(10000, "10,000");
failures += !test(100000, "100,000");
failures += !test(1000000, "1,000,000");
failures += !test(10000000, "10,000,000");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
The regex uses 2 lookahead assertions:
- a positive one to look for any point in the string that has a multiple of 3 digits in a row after it,
- a negative assertion to make sure that point only has exactly a multiple of 3 digits. The replacement expression puts a comma there.
For example, if you pass it 123456789.01
, the positive assertion will match every spot to the left of the 7 (since 789
is a multiple of 3 digits, 678
is a multiple of 3 digits, 567
, etc.). The negative assertion checks that the multiple of 3 digits does not have any digits after it. 789
has a period after it so it is exactly a multiple of 3 digits, so a comma goes there. 678
is a multiple of 3 digits but it has a 9
after it, so those 3 digits are part of a group of 4, and a comma does not go there. Similarly for 567
. 456789
is 6 digits, which is a multiple of 3, so a comma goes before that. 345678
is a multiple of 3, but it has a 9
after it, so no comma goes there. And so on. The \B
keeps the regex from putting a comma at the beginning of the string.
@neu-rah mentioned that this function adds commas in undesirable places if there are more than 3 digits after the decimal point. If this is a problem, you can use this function:
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0 , "0");
failures += !test(0.123456 , "0.123456");
failures += !test(100 , "100");
failures += !test(100.123456 , "100.123456");
failures += !test(1000 , "1,000");
failures += !test(1000.123456 , "1,000.123456");
failures += !test(10000 , "10,000");
failures += !test(10000.123456 , "10,000.123456");
failures += !test(100000 , "100,000");
failures += !test(100000.123456 , "100,000.123456");
failures += !test(1000000 , "1,000,000");
failures += !test(1000000.123456 , "1,000,000.123456");
failures += !test(10000000 , "10,000,000");
failures += !test(10000000.123456, "10,000,000.123456");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
@t.j.crowder pointed out that now that JavaScript has lookbehind (support info), it can be solved in the regular expression itself:
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}
function test(x, expect) {
const result = numberWithCommas(x);
const pass = result === expect;
console.log(`${pass ? "✓" : "ERROR ====>"} ${x} => ${result}`);
return pass;
}
let failures = 0;
failures += !test(0, "0");
failures += !test(0.123456, "0.123456");
failures += !test(100, "100");
failures += !test(100.123456, "100.123456");
failures += !test(1000, "1,000");
failures += !test(1000.123456, "1,000.123456");
failures += !test(10000, "10,000");
failures += !test(10000.123456, "10,000.123456");
failures += !test(100000, "100,000");
failures += !test(100000.123456, "100,000.123456");
failures += !test(1000000, "1,000,000");
failures += !test(1000000.123456, "1,000,000.123456");
failures += !test(10000000, "10,000,000");
failures += !test(10000000.123456, "10,000,000.123456");
if (failures) {
console.log(`${failures} test(s) failed`);
} else {
console.log("All tests passed");
}
.as-console-wrapper {
max-height: 100% !important;
}
(?<!\.\d*)
is a negative lookbehind that says the match can't be preceded by a .
followed by zero or more digits. The negative lookbehind is faster than the split
and join
solution (comparison), at least in V8.
Solution 2
I'm surprised nobody mentioned Number.prototype.toLocaleString. It's implemented in JavaScript 1.5 (which was introduced in 1999) so it's basically supported across all major browsers.
var n = 34523453.345;
console.log(n.toLocaleString()); // "34,523,453.345"
It also works in Node.js as of v0.12 via inclusion of Intl
If you want something different, Numeral.js might be interesting.
Solution 3
Below are two different browser APIs that can transform Numbers into structured Strings. Keep in mind that not all users' machines have a locale that uses commas in numbers. To enforce commas to the output, any "western" locale may be used, such as en-US
let number = 1234567890; // Example number to be converted
⚠️ Mind that javascript has a maximum integer value of 9007199254740991
toLocaleString
// default behaviour on a machine with a local that uses commas for numbers
let number = 1234567890;
number.toLocaleString(); // "1,234,567,890"
// With custom settings, forcing a "US" locale to guarantee commas in output
let number2 = 1234.56789; // floating point example
number2.toLocaleString('en-US', {maximumFractionDigits:2}) // "1,234.57"
NumberFormat
let number = 1234567890;
let nf = new Intl.NumberFormat('en-US');
nf.format(number); // "1,234,567,890"
From what I checked (Firefox at least) they are both more or less same regarding performance.
⚡ Live demo: https://codepen.io/vsync/pen/MWjdbgL?editors=1000
Solution 4
I suggest using phpjs.org 's number_format()
function number_format(number, decimals, dec_point, thousands_sep) {
// http://kevin.vanzonneveld.net
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfix by: Michael White (http://getsprink.com)
// + bugfix by: Benjamin Lupton
// + bugfix by: Allan Jensen (http://www.winternet.no)
// + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + bugfix by: Howard Yeend
// + revised by: Luke Smith (http://lucassmith.name)
// + bugfix by: Diogo Resende
// + bugfix by: Rival
// + input by: Kheang Hok Chin (http://www.distantia.ca/)
// + improved by: davook
// + improved by: Brett Zamir (http://brett-zamir.me)
// + input by: Jay Klehr
// + improved by: Brett Zamir (http://brett-zamir.me)
// + input by: Amir Habibi (http://www.residence-mixte.com/)
// + bugfix by: Brett Zamir (http://brett-zamir.me)
// + improved by: Theriault
// + improved by: Drew Noakes
// * example 1: number_format(1234.56);
// * returns 1: '1,235'
// * example 2: number_format(1234.56, 2, ',', ' ');
// * returns 2: '1 234,56'
// * example 3: number_format(1234.5678, 2, '.', '');
// * returns 3: '1234.57'
// * example 4: number_format(67, 2, ',', '.');
// * returns 4: '67,00'
// * example 5: number_format(1000);
// * returns 5: '1,000'
// * example 6: number_format(67.311, 2);
// * returns 6: '67.31'
// * example 7: number_format(1000.55, 1);
// * returns 7: '1,000.6'
// * example 8: number_format(67000, 5, ',', '.');
// * returns 8: '67.000,00000'
// * example 9: number_format(0.9, 0);
// * returns 9: '1'
// * example 10: number_format('1.20', 2);
// * returns 10: '1.20'
// * example 11: number_format('1.20', 4);
// * returns 11: '1.2000'
// * example 12: number_format('1.2000', 3);
// * returns 12: '1.200'
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
toFixedFix = function (n, prec) {
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
var k = Math.pow(10, prec);
return Math.round(n * k) / k;
},
s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
UPDATE 02/13/14
People have been reporting this doesn't work as expected, so I did a JS Fiddle that includes automated tests.
Update 26/11/2017
Here's that fiddle as a Stack Snippet with slightly modified output:
function number_format(number, decimals, dec_point, thousands_sep) {
// http://kevin.vanzonneveld.net
// + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfix by: Michael White (http://getsprink.com)
// + bugfix by: Benjamin Lupton
// + bugfix by: Allan Jensen (http://www.winternet.no)
// + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// + bugfix by: Howard Yeend
// + revised by: Luke Smith (http://lucassmith.name)
// + bugfix by: Diogo Resende
// + bugfix by: Rival
// + input by: Kheang Hok Chin (http://www.distantia.ca/)
// + improved by: davook
// + improved by: Brett Zamir (http://brett-zamir.me)
// + input by: Jay Klehr
// + improved by: Brett Zamir (http://brett-zamir.me)
// + input by: Amir Habibi (http://www.residence-mixte.com/)
// + bugfix by: Brett Zamir (http://brett-zamir.me)
// + improved by: Theriault
// + improved by: Drew Noakes
// * example 1: number_format(1234.56);
// * returns 1: '1,235'
// * example 2: number_format(1234.56, 2, ',', ' ');
// * returns 2: '1 234,56'
// * example 3: number_format(1234.5678, 2, '.', '');
// * returns 3: '1234.57'
// * example 4: number_format(67, 2, ',', '.');
// * returns 4: '67,00'
// * example 5: number_format(1000);
// * returns 5: '1,000'
// * example 6: number_format(67.311, 2);
// * returns 6: '67.31'
// * example 7: number_format(1000.55, 1);
// * returns 7: '1,000.6'
// * example 8: number_format(67000, 5, ',', '.');
// * returns 8: '67.000,00000'
// * example 9: number_format(0.9, 0);
// * returns 9: '1'
// * example 10: number_format('1.20', 2);
// * returns 10: '1.20'
// * example 11: number_format('1.20', 4);
// * returns 11: '1.2000'
// * example 12: number_format('1.2000', 3);
// * returns 12: '1.200'
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
toFixedFix = function (n, prec) {
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
var k = Math.pow(10, prec);
return Math.round(n * k) / k;
},
s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
var exampleNumber = 1;
function test(expected, number, decimals, dec_point, thousands_sep)
{
var actual = number_format(number, decimals, dec_point, thousands_sep);
console.log(
'Test case ' + exampleNumber + ': ' +
'(decimals: ' + (typeof decimals === 'undefined' ? '(default)' : decimals) +
', dec_point: "' + (typeof dec_point === 'undefined' ? '(default)' : dec_point) + '"' +
', thousands_sep: "' + (typeof thousands_sep === 'undefined' ? '(default)' : thousands_sep) + '")'
);
console.log(' => ' + (actual === expected ? 'Passed' : 'FAILED') + ', got "' + actual + '", expected "' + expected + '".');
exampleNumber++;
}
test('1,235', 1234.56);
test('1 234,56', 1234.56, 2, ',', ' ');
test('1234.57', 1234.5678, 2, '.', '');
test('67,00', 67, 2, ',', '.');
test('1,000', 1000);
test('67.31', 67.311, 2);
test('1,000.6', 1000.55, 1);
test('67.000,00000', 67000, 5, ',', '.');
test('1', 0.9, 0);
test('1.20', '1.20', 2);
test('1.2000', '1.20', 4);
test('1.200', '1.2000', 3);
.as-console-wrapper {
max-height: 100% !important;
}
Solution 5
This is a variation of @mikez302's answer, but modified to support numbers with decimals (per @neu-rah's feedback that numberWithCommas(12345.6789) -> "12,345.6,789" instead of "12,345.6789"
function numberWithCommas(n) {
var parts=n.toString().split(".");
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}
Comments
-
Elias Zamaria over 2 years
I am trying to print an integer in JavaScript with commas as thousands separators. For example, I want to show the number 1234567 as "1,234,567". How would I go about doing this?
Here is how I am doing it:
function numberWithCommas(x) { x = x.toString(); var pattern = /(-?\d+)(\d{3})/; while (pattern.test(x)) x = x.replace(pattern, "$1,$2"); return x; }
Is there a simpler or more elegant way to do it? It would be nice if it works with floats also, but that is not necessary. It does not need to be locale-specific to decide between periods and commas.
-
Eric Petroelje about 12 yearsVery cool, did notice that it has problems with numbers that have more than 3 places after the decimal point though.
-
neu-rah almost 12 yearstry numberWithCommas(12345.6789) -> "12,345.6,789" i dont like it
-
Aki143S over 11 yearsHi.. This example is great. But it will put commas for the decimal part too. just an edit: function formatNumber( num ) { var decimalPart = ''; num = num.toString(); if ( num.indexOf( '.' ) != -1 ) { decimalPart = '.'+ num.split( '.' )[1]; num = parseInt(num.split( '.' )[0]); } var array = num.toString().split( '' ); var index = -3; while ( array.length + index > 0 ) { array.splice( index, 0, ',' ); // Decrement by 4 since we just added another unit to the array. index -= 4; } return array.join( '' ) + decimalPart; };
-
balexandre over 11 yearsto make it more readable, never use 2
return
s, instead do:return myString.length > 3 ? myString.substring(0, myString.length - 3) + "," + myString.substring(myString.length - 3) : myString;
-
Mugen about 11 yearsIt doesn't work well with fractions, we wouldn't want to have commas after the decimal point
-
Dmitrij Golubev almost 11 yearsSmall improvement that fix after '.' problem '123456789.01234'.replace(/\B(?=(?=\d*\.)(\d{3})+(?!\d))/g, '_')
-
Andrew S almost 11 yearsNot that I marked it down, but I believe people did so because it does not work. As it stands I find even some of your tests to not work.
-
Kerry Jones almost 11 years@Andrew S -- Only 1 person has marked it down. It does work, I have used it in my own code many times. It's also not my code (nor my tests), I referenced the site that it comes from, which is a well-known site. Perhaps they have an updated version of it) as the code you are looking at is 3 years old.
-
vbwx almost 11 yearsVery nice, I borrowed the first method ;) But it does not produce a correct result when you want to use a European format and the number is fractional. Line 5 should be:
var parts = this.toFixed(decimals).toString().split('.');
-
None almost 11 yearsYou are right! toFixed() changes the comma to a period and so the '.' should be used instead of
var dec_point
. Thanks for pointing that out. -
csigrist almost 11 yearsI upvoted, but upon further research found some problems with this answer. The performance is not as good as a regex formatter. See the following link: jsperf.com/number-formatting-with-commas. Also trying to get trailing zeros as decimal places is problematic.
-
uKolka almost 11 years@csigrist Good points, but it's not as bad as it seems. Speed is browser dependent. In FF or Opera it performs good. I sucks in Chrome though. As for zeroes:
var number = 123456.000; number.toLocaleString('en-US', {minimumFractionDigits: 2}); "123,456.00"
Those options don't work in FF or Safari though. -
Ahrengot almost 11 yearsWhat a beautiful solution. A simple and nice addon is the seperator as a second argument, as numbers aren't seperated by commas in every language.
-
synthesizerpatel over 10 yearsIntl.NumberFormat() seems a little more up-to-date since it uses locale doodads.
-
Chris Betti over 10 yearsCould you post the solution using CSS only & spans?
-
chovy over 10 yearscan you make an npm module for this?
-
Kerry Jones over 10 years@ernix - The operator asked for JavaScript, that answer I gave is JavaScript. This is a JavaScript interpretation of a PHP function.
-
T Nguyen over 10 yearsThe performance difference may or may not be an issue, depending on the context. If used for a giant table of 1000 results then it will be more important but if only used for a single value, the difference is negligible. But the advantage is that it's locale-aware, so someone in Europe would see 34.523.453,345 or 34 523 453,345. This would be more important on a site with visitors from many countries.
-
ernix over 10 years@Kerry, this
number_format('str')
returns '0'. I think it's far from interpretation. -
Kerry Jones over 10 years@ernix - it works exactly as expected with the example the OP gave. I put a fiddle so you can see.
-
Kerry Jones over 10 years@ernix - Okay, but the point is that it does exactly what the OP asked for. It is from another site (not maintained by me, and I've stated this previously), and when giving it proper variables, it works exactly as stated. If you believe that to be a bug, contact phpjs.org or see if they have an updated version.
-
ryan j about 10 yearsAppending a null string rather than calling .toString() is generally a bit faster, so you can return (x+'').replace(/\B(?=(\d{3})+(?!\d))/g, ','); Also doesn't throw a JS error if you pass it null or undefined, but typecasting does mean you turn undefined into the string 'undefined' etc. which is something to be aware of.
-
ryan j about 10 yearswas going to do a quick jsfiddle of append vs .toString() but somebody else got there first! if you're curious jsperf.com/tostring-vs-appending-empty-string/3
-
hypno7oad about 10 yearsIf you change the first line to var
var parts = (x) ? (x+"").split(".") : [""];
, then you can pass this as a map function over an array of values like so[1000].map(numberWithCommas)
. -
Elias Zamaria about 10 years@hypno7oad, my function seems to work fine with
map
the way it is now. Your change just seems to make it behave strangely when 0 is passed. -
hypno7oad about 10 years@EliasZamaria I was trying to handle undefined or null values, since the current function throws errors when it receives them. This could be important when working with datasets that include them, which is how I stumbled upon this thread. BTW, thanks for the answer. It helped me out with my current task. However, you're right that my addition breaks down when it encounters 0. For the sake of brevity, I tried to rely solely on the 'truthiness' of x, which obviously was wrong since 0 is falsy. Try this instead
var parts = (x || x === 0) ? (x+"").split(".") : [""];
-
wrossmck about 10 yearsthis doesn't work for
-123456
it gives-1,234,56
-
wrossmck about 10 yearsthis doesn't work with
format(-123456)
it gives-,123,456
-
wrossmck about 10 yearsthis doesn't work with
commafy(-123456)
it gives-,123,456
-
Wayne about 10 yearsFixed (although there is probably a more elegant way to do it without checking for the sign every time). In any event, the update makes this work with negative numbers.
-
wrossmck about 10 years
-
eliajf about 10 yearsI improved this to also handle exponential notation and thought I'd share it: var parts = x.toString().split("."); var e = false; if (parts.length == 1) { parts = x.toString().split("E"); e = true; } parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); return (e ? parts.join("E") : parts.join("."));
-
Petr Havlik almost 10 yearsthis is just crazy :)
-
Ryan Shea almost 10 yearsThis is fine but it's specific to countries that use commas as thousand separators (many use periods). Take a look at @ukolka's solution, which uses the builtin function toLocaleString() and auto-converts a number based on the locale.
-
Tomáš Zato almost 10 yearsAwesome. Finally an answer with native function. And what more, this one displays properly in different countries with different separators (in Czech Republic we write
X XXX XXX,YYY
). -
Ariel almost 10 years@J.Money The .toString is unnecessary, toFixed already returns a string.
-
Elias Zamaria over 9 yearsWhat does this do that my answer doesn't? The regex looks slightly different but it looks like it should do the same thing.
-
Shawn J. Molloy over 9 yearsHaha I agree with petr its fun to look at though.
-
Admin over 9 yearsThis could possibly be an answer to an independent question. You are encouraged to answer your own question, to share knowledge
-
Blaine Kasten over 9 yearsWhile this would be awesome if we could use a simple built-in function, it has terrible browser implementation. For Example, IE 8-10 and all Safari doesnt support this
-
ROMANIA_engineer over 9 yearsFor
var n = 12345.54321
Chrome prints12,345.543
without 2 decimals. -
uKolka over 9 years@curiosu please read the docs and previous comments.
var number = 12345.54321; number.toLocaleString('en-US', {maximumFractionDigits: 10});
-
traditional over 9 yearsThis is elegant. Exactly what I was looking for.
-
Mahn over 9 years@BlaineKasten there's a fully compatible polyfill for older browsers available here: github.com/andyearnshaw/Intl.js it's huge, but it works.
-
Vlad over 9 yearsFrom blog.tompawlak.org/number-currency-formatting-javascript? Known issue: formatNumber(0.123456) = 0.123,456 The absence of lookbehind in JS makes it difficult to fix it with an elegant regex.
-
Vlad over 9 years@DmitrijGolubev Doesn't work for integers. Perhaps forcing the decimal point would be the solution.
-
2540625 about 9 years@DmitrijGolubev: Your solution works for the number
42
, but fails for the number2398512
. Any idea why? -
hoju almost 9 yearstoLocaleString() has poor mobile support, better to use your own javascript function for now
-
steampowered almost 9 yearsthis inspired me to npm install numeral
-
The_Black_Smurf almost 9 yearsThe OP was asking for a coma separator. As many languages doesn't use coma as thousands separator, you may want to use a specific language that has a coma separator:
toLocaleString('en')
-
Marcio almost 9 yearsworks only well if you dont have float number with more than 3 numbers after the separator in this case a dot. Otherwise it adds a comma also. "1234567890.1234567890".replace(/\B(?=(\d{3})+\b)/g, ",") This would not work for example. Returns "1,234,567,890.1,234,567,890"
-
vsync over 8 yearsI don't know why you've mentioned PHP here at all, or given a prototipical function which already exists
-
None over 8 years@vsync The most important reason of all... browser compatibility.
-
vsync over 8 years@J.Money - first, it doesn't explain what PHP has to do with that, and second, you didn't mention that
numberFormat
is already in ES4, and what browsers does it supports:chrome 24+, FF 29+, IE11+
. only then you should provide an optional polyfill, whom not everyone needs. -
Kyle Chadha over 8 yearsWorks well for currency though! Just round your digits prior to adding commas.
-
fregante over 8 yearsThis is great! Thanks for putting together the jsperf
-
Kevin over 8 yearsAvailable via a pollyfill CDN (only returns what is needed based on useragent): cdn.polyfill.io/v2/polyfill.min.js?features=Intl
-
srobinson over 8 yearsUpdate for googlers:
toLocaleString
works in Node.js as of v0.12 via the inclusion of Intl. -
BrunoLM over 8 yearsThis website, regex101 explains regex expressions. Might help.
-
FeFiFoFu over 8 yearsI added s.toString() at beginning of function so it can accept numbers too, not just strings. This is my preferred answer because it is readable, concise, and has none of the bugs the regex answers seem to have.
-
NiCk Newman over 8 yearsThis snippet is an absolute monster, out performs everything.
-
MSC about 8 yearsHmm. Can't get it to work in Chrome 48 console. I type:"1234567".toLocaleString('en-US', {minimumFractionDigits: 2}); and get "1234567".
-
uKolka about 8 years@MSC you should try
parseInt("1234567", 10).toLocaleString('en-US', {minimumFractionDigits: 2})
ornew Number("1234567").toLocaleString('en-US', {minimumFractionDigits: 2})
instead. It doesn't work because you use it on a string, not a number. -
vsync about 8 yearsBrowsers support is always mentioned at the bottom of each MDN page, which I've linked to.
-
Dennis Heiden about 8 yearsPerfect for me, just added a new line to remove formatting before processing.
-
Stefan Steiger about 8 yearsIf you add x = parseFloat(x).toFixed(2) then you can ensure there's never more than 3 digits after the decimal point
-
Debashis almost 8 yearsthis allows characters like abcdef and so on.. which should be restricted.
-
Debashis almost 8 yearsthis allows characters like abcdef and so on.. which should be restricted
-
Dandalf almost 8 yearsYou could still show commas while allowing copy/paste the input in the original format by using css:
.thousandsSeparator:before{ content: ','; }
JSFiddle: jsfiddle.net/Dandalf/ze6agw7v -
Marcin Zukowski almost 8 yearsOh wait. It just adds a comma before. Your still render using the Javascript from my example. So I'm not sure what you mean.
-
dandavis almost 8 yearsbasic
toLocaleString
works on safari, options don't -
yar1 almost 8 yearsDownvoted because answer should just be Number(n).toLocaleString()
-
Henders almost 8 years@yar1 what if you are planning on using that in Safari? Then you just get the number back with no commas.
-
Will Bowman over 7 yearsHad issues formatting large numbers with toLocaleString, this worked great (with polyfill)
-
mayatron over 7 yearsAs others have noted,
number.toLocaleString
does not work for all browsers, nor in PhantomJS. Number.toLocaleString() doesn't apply appropriate formatting -
mayatron over 7 yearsAlso
number.toLocaleString
does not work in PhantomJS. Number.toLocaleString() doesn't apply appropriate formatting -
Josh over 7 years@jcollum Could you specify which version of Node you're referring to? I'm working with v4.4.7 and it's works perfectly.
-
David over 7 yearsIf you add zero decimal e.g. 0.30000000004 it returns 0.30,000,000,004
-
Elias Zamaria over 7 years@David, did you read my whole answer, including the part where I mention neu-rah's observation that it inserts commas in undesirable places, and my fix for that?
-
Mike 'Pomax' Kamermans over 7 yearsthe
toLocaleString
solution should probably also include the desired locale, sotoLocaleString("en")
, because the English pattern uses commas. However, iftoLocaleString()
without locale indicator is run in France, then it'll yield periods instead of commas because that's what is used to separate thousands locally. -
Andy about 7 yearsBe aware that the polyfill only works with numbers that have at most 3 decimals. For eg:
0.12345
will output0.12,345
. A good implementation for this can be found in the underscore.string -
Sinan about 7 yearsyou're right, putting a
value > 1000
to the if condition fixes that case, however this was a poc and of course better tested versions can be found elsewhere, thanks for pointing out. -
Andy about 7 yearsIt's not sufficient to put
value > 1000
, because it would be the same for any number and more than 3 decimals. eg1000.12345
returns1,000.12,345
. Your answer is great and on the right path, but just not complete. I was only trying to point out for other people that may stumble on your answer and just copy/pasta it without testing with different input data. -
Sinan about 7 yearsalright, this needed another edit :) I agree, but now at least it should work for the most cases.
-
adi518 about 7 years@EliasZamaria I don't understand why you didn't incorporate neu-rah's solution, but rather offer it as an improvement? I'd understand if that solution involved more than a few lines of code.
-
Admin about 7 yearsI've updated this since JavaScript's parseFloat stops at the first comma it sees, so if you passed in a string with commas, it would not see the entire string as a number... jsfiddle.net/xc3qh35z/63 and I needed a function that could handle the text values from HTML input elements, which will often already have commas and decimal points in them. The modification removes ALL non-numeric characters except decimal points before generating the new string, so it should handle US numbers other than currency out of the box.
-
Shrijan Tiwari almost 7 yearsIt Adds , After Decimal point : 12.3456".replace(/\B(?=(\d{3})+\b)/g, ",") == 12.3,456
-
Donald Duck almost 7 yearsWhile this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.
-
parlad almost 7 yearshi guys , i implement this for textbox and i can only enter 5 digit , any specific reason? Not good with regex. (not saying this is wrong, just need clue ) Thanks
-
kenberkeley almost 7 years123456789.123456789.toString().replace(/(\d)(?=(\d{3})+\.)/g, '$1,') => 123,456,789.12345679
-
James Hulse almost 7 yearsI have taken this a step further by displaying un-selectable commas: jsfiddle.net/ovfd83py/13
-
ush189 over 6 yearsLink does not work anymore. But looks similar to this one: openexchangerates.github.io/accounting.js
-
Elias Zamaria over 6 yearsThis doesn't work. I ran
makedollars(12345.67)
and got an array of strings:["12", "345.67", ".67"]
. -
Peter S McIntyre over 6 yearsI should have split on "." Then added the second part back In after. I forgot about decimals.
-
A-Diddy over 6 yearsAs of this comment,
.toLocaleString()
doesn't appear to work in the latest version of Chrome (v60.0). -
Stephen over 6 years@A-Diddy just tried this in Chrtome 61 and it works fine
-
A-Diddy over 6 yearsSkuld & all, wth... I just confirmed that you're correct,
.toLocalString()
appears to now work as described above in Chrome v61. How weird that v61 comes out with support minutes after I posted that comment. Talk about Big Brother... Google engineers are on it. -
Dustin Sun over 6 yearsMy answer was updated in response to your comments. Thanks!
-
SharpC over 6 years
minimumFractionDigits: 2
can also be added to ensure a fixed number of decimal places stackoverflow.com/questions/31581011/… -
Ralph David Abernathy over 6 yearsNice script, but it does not work with negative numbers.
-
Young-hwi about 6 yearsIf the intention is displaying 123456.789 as "١٢٣٬٤٥٦٫٧٨٩" when language code is "ar", "၁၂၃,၄၅၆.၇၈၉" for language code "my", then using `.toLocaleString()'. However, if you just want to insert thousand separating commas, then you will want to use Devin G Rhode's solution.
-
oz. about 6 yearsThis one is perfect except for one issue. It would be better if there was an extra, optional argument for rounding vs. truncating. Rounding isn't always the desired approach.
-
Elias Zamaria almost 6 yearsI think it would be a good idea to make this function take its input as a parameter instead of relying on a global variable named
cash
. And what is the'Ksh '
for in the return statement? -
Elias Zamaria almost 6 yearsI tried
commas(12345.67)
and got "12,345.6700000000000728". -
aleclarson almost 6 years@EliasZamaria whoops! forgot about imprecise arithmetic. fixed :)
-
Jacob Stamm almost 6 yearsHey look, you're an open-source contributor :)
-
Jared Smith almost 6 yearsThis is the correct, portable, native answer. Wish I could upvote more than once.
-
jeesty almost 6 yearsthe answer num.toLocaleString() below is more correct, because it is built-in and because it accounts for cultural differences. Europe uses commas in numbers differently from the US
-
Jghorton14 almost 6 yearsThe parenthesis in
(x)
is not necessary. If only one variable is presentx
will suffice. -
Tharanga almost 6 yearsThis piece of JS is awesome. It's better than using
toLocaleString()
becausetoLocaleString()
does not affect on the numbers placed in another string.(eg: The value is greater than 15000 but ...)
but this piece of code does. Thanks. -
Edgar Quintero almost 6 yearsThis doesn't work if you are dynamically typing. If you just give it a value it works, but if you're feeding a value constantly dynamically the commas are added in the wrong place.
-
Tính Ngô Quang almost 6 yearsI have updated the demo below my answer. When entering a dynamic value in a textbox. you test try @EdgarQuintero
-
Hanna over 5 yearsWhile
9007199254740991
is theNumber.MAX_SAFE_INTEGER
you can usetoLocaleString()
up toNumber.MAX_VALUE
which is1.7976931348623157e+308
. Anything larger than this will return∞
. -
codingguy3000 over 5 yearsThis doesn't work... Consider... 9429700000 With this code you get 9,429,700,0000
-
mmla over 5 yearsNot a good option if you're a functional programmer because it does not work with literal number objects, just variables.
-
uKolka over 5 years@mmla By option you mean JavaScript? It's a mixed-paradigm language. This does work on literals, maybe not in ways you're expecting. Try
(123123).toLocaleString()
-
Shanteshwar Inde about 5 yearsWhile this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.Read this.
-
Bathri Nathan about 5 years@ShanteshwarInde i will add additional context to improve the answer sure
-
Arad almost 5 yearsThank you, sir. This is exactly what I needed.
-
Jignesh Sanghani almost 5 years
fn.substr(0, i)
replace withn.substr(0, i)
and alsonumber.toFixed(dp).split('.')[1]
replace withparseFloat(number).toFixed(dp).split('.')[1]
. because when i use directly it's give me en error. please update your code -
OG Sean almost 5 yearswhy did you write the function with const and => ?
-
Igor Bykov almost 5 years@OGSean I always do since it's the most convenient way of declaring variables & functions. Also, I think it helps to keep the code cleaner & shorter.
-
mjs over 4 yearsflawed. number grows. an exampel call would have been great!
-
mjs over 4 yearsswitching ceil to floor fixed that but unsure what other issues will arise.
-
Im Batman over 4 yearsNote. this won't work with Android if you are developing React Native app.
-
bmacnaughton over 4 yearsThe Number(n).toLocaleString() seems the best answer but you'd probably want to use something like new Intl.NumberFormat('en-US').format(n) rather than stripping off dollar signs and decimals if all the user wants is commas in their number.
-
Lonnie Best over 4 years@bmacnaughton : That's a good point when you're not dealing with money. However, if you're dealing with money, and just "don't want the leading dollar sign", Number(1000.50).toLocaleString() produces '1,000.5', which removes the insignificant zero that's typically kept when displaying money values. Good comment though: everyone should know what you've said.
-
Elias Zamaria over 4 yearsThis is not code golf. I think it is OK to use some spaces and newlines to make your code more readable, even if they are not strictly required.
-
MMMahdy-PAPION over 4 years@elias-zamaria check it out now by the new function, i removed negative behind look because not support in all browsers
-
mjs over 4 yearsi just saw your comment, however, i remember the issue was not that simple. ceil was also flawed in some cases. just checked. if the number is negative. therefore abs should come before floor.
-
mjs over 4 yearsTry Math.floor(-75.1) ;)
-
Andrew over 4 yearsNote: You may need to cast your number string to an int or float first, i.e.
parseInt(123456, 10).toLocaleString()
orparseFloat(123456.789012, 10).toLocaleString()
. Also, in the latter case,.toLocaleString()
will by default limit the number of decimal digits. -
moto about 4 years@codingguy3000 The function posted at the end of the answer does not have this problem.
-
T.J. Crowder about 4 yearsNow that JavaScript is getting lookbehind, the digits-after-the-decimal part can be solved in the regex rather than using
split
andjoin
:.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")
. I've updated the answer to show that as well. Being a variable length lookbehind I worried about performance, but it beatssplit
andjoin
. -
Junius L. about 4 years@T.J.Crowder it's breaking in Safari
Invalid regular expression: invalid group specifier name
-
T.J. Crowder about 4 years@JuniusL. - See the support info linked in the answer.
-
doublejosh about 4 yearsNot a good solution! Use
toLocaleString()
and stop being North American focused. UGH. -
Suraj Dalvi almost 4 yearsthis not working node js. It is not giving response in Indian format
-
Yakov Kemer almost 4 yearsbe careful with this code. it doesn't work in firefox
-
hendr1x almost 4 yearsDoesnt work with numbers that have long decimal values (just tested with four : ie : 12223.0234)
-
Elias Zamaria almost 4 years@hendr1x what is the problem? This answer mentions that the first snippet puts commas in undesirable places if there are more than 3 digits after the decimal point. The 2nd and 3rd work fine, and return "12,223.0234".
-
Jee Mok almost 4 yearsto have two decimals:
x.toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-
Aaron Angle over 3 yearsThis does not work in safari. Broke my entire application and took me forever to figure out this was the problem
-
Ivan Juarez over 3 yearsTake your Like~!!
-
pishpish over 3 yearsKeep in mind that
toLocaleString
is implementation specific - you will get different results across browsers/environments. -
Mahmood Afzalzadeh over 3 yearsSaved my time and
toLocaleString
is useful and works on FireFox and Chrome very good. -
Elias Zamaria over 3 yearsThat is telling me "Uncaught TypeError: number is not iterable". Maybe you need to call
toString
on the number. -
Robo Robok over 3 years@EliasZamaria sorry, I used a string in my case. Updated my answer to convert to string.
-
Elias Zamaria over 3 yearsI tried 12.34 as the number and it returned
12,.34
. -
Robo Robok over 3 yearsI thought it was only meant to work with decimals. Updated for you.
-
beliha over 3 yearsDoesn't work in IE11! It has an issue with the regEx for some reason: "Unexpected quantifier"
-
Nader Gharibian Fard over 3 yearstnx brother.. var nf = new Intl.NumberFormat(); nf.format(number); // "1,234,567,890" it's work
-
Dzmitry Vasilevsky over 3 years@EliasZamaria please edit you answer about lookbehind It can't be used in enterprise still. The latest Safari doesn't support it. And it can't be polyfilled. Many guys above broke their apps because of that suggestion as well as one from my team. Please add that it is not yet ready to use like with uppercase characters.
-
Elias Zamaria over 3 years@DzmitryVasilevsky I didn't add the lookbehind stuff to this answer. I can remove it, but I think it is useful, and this answer still has my original solution, for interpreters that don't support lookbehind.
-
Dzmitry Vasilevsky over 3 years@EliasZamaria The fact is that it is causing problems for seekers. I don't think this should be removed but rather edited like: t.j.crowder pointed out that there is a cutting edge way to solve that. Be aware that it is STILL NOT SUPPORTED by some of the modern browsers - support info)! Modern JavaScript has lookbehind, it can be solved in the regular expression itself...
-
Elias Zamaria about 3 years@DzmitryVasilevsky is the "support info" link that is there now good enough? Or does it need to be made more obvious and noticeable?
-
Dzmitry Vasilevsky about 3 years@EliasZamaria I think should be more noticeable. BTW thanks for cooperation
-
Hissvard about 3 yearsThis is perfect. I kept looking and only finding incredibly bloated libraries that didn't even let me change thousands and decimal separator.
-
Maor Ben about 3 yearsYou could also loop through
x.toString().length
and usex[i]
-
serraosays about 3 yearsThis is the right answer, people are wildly overcomplicating this.
toLocaleString()
is built for this exact use case. -
Elias Zamaria almost 3 yearsWhat is that supposed to do? I get errors like "123.split is not a function".
-
anarchist almost 3 yearsYou can use it to convert comma string values to fractional numbers.
console.log(parseFloat(parseFloat(('123,56').split(',').join('.')).toFixed(2)));
-
Andy Borgmann almost 3 yearsThis was my favorite of the solutions.
-
Elias Zamaria almost 3 yearsFYI it looks like that is already mentioned here: stackoverflow.com/a/32154217/28324
-
ladieu over 2 yearsonly works if you pass it a string.. an easy fix but just wanted to note it
-
Cees Timmerman over 2 years
-
AncientSwordRage over 2 yearsI think adding a link to
toLocaleString
, uKolka's answer or explaining why this might be better than that function would be good. -
AncientSwordRage over 2 yearsThe currency formatting massively skews this: jsben.ch/u4gk0
-
kmsheng about 2 yearsThis solution DOES NOT work for safari and iphone chrome. It will break your entire application and it's hard to debug in mobile. Please consider down-voting this solution to save people's time.
-
Adam Ellis almost 2 yearsThe answer is good for some browsers, but since it doesn't work in Safari on Mac/iOS (as of June 2022), it should not be the top accepted answer. A big obvious note should be added to say that it shouldn't be used in a production environment.
-
Cybernetic almost 2 yearsNone of these work with the number 57024.00000000001
-
Elias Zamaria almost 2 years@Cybernetic I just ran
(57024.00000000001).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")
and got57,024.00000000001
. -
Cybernetic almost 2 years@EliasZamaria interesting....I get
57,024.00,000,000,001
.... I am on Chrome Version 102.0.5005.115 (Official Build) (arm64) -
Elias Zamaria almost 2 years@Cybernetic are you sure you are using one of the last 2
numberWithCommas
functions in this answer (not the first)? -
Cybernetic almost 2 years@EliasZamaria you're correct, my apologies. I was using (x).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");