You need to replace (remove) the dots first in the thousands separator, then take care of the decimal:

Copyfunction isNumber(n) {
    'use strict';
    n = n.replace(/\./g, '').replace(',', '.');
    return !isNaN(parseFloat(n)) && isFinite(n);
}
Answer from rink.attendant.6 on Stack Overflow
🌐
Medium
medium.com › @noffybarudwale › javascript-format-numbers-with-commas-and-decimals-86b68ec5b180
JavaScript : Format numbers with commas and decimals. | by Nofij Barudwale | Medium
October 13, 2021 - There are many different ways of printing an integer with a comma as a thousands separators in JavaScript. I found a good function that details how to and thought I would reproduce it here. It basically takes any number and turns it into formatted string with the thousands separated by commas and decimals.
Discussions

How do I change the decimal separator to a comma on a number input field?
I can't work out how to change the decimal separator to a comma. Any ideas? In most of Europe we format our numbers like 1.000,00 instead of 1,000.00. It's a small thing, but is very frustrating because when entering numbers if I key 99,95 then it is entered as 9,995.00 More on community.retool.com
🌐 community.retool.com
1
1
April 28, 2022
Parsing a number that uses comma as the decimal separator
Hi, I have a seemingly small task that I can't seem to get right. I need to parse the response from an external API. One field in the response is a string that contains a number that uses comma , a... More on github.com
🌐 github.com
1
2
March 20, 2024
What is the best way to handle a period or comma as a thousand or decimal separator in web applications?
The backend should only send raw number, the frontend format depends on locale More on reddit.com
🌐 r/webdev
6
3
August 8, 2023
javascript - How can I format a number with commas as thousands separators? - Stack Overflow
You may use the expressions that ... modern JavaScript). ... Thanks to everyone for their replies. I have built off of some of the answers to make a more "one-size-fits-all" solution. The first snippet adds a function that mimics PHP's number_format() to the Number prototype. If I am formatting a number, I usually want decimal places so the function takes in the number of decimal places to show. Some countries use commas as the decimal and decimals as the thousands separator so the function ... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Byby
byby.dev › js-format-numbers-commas
How to format numbers with commas in JavaScript
The usage of commas (,) and periods (.) as decimal separators and thousands separators varies based on the conventions of different regions and countries.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Intl › NumberFormat
Intl.NumberFormat - JavaScript - MDN Web Docs
const number = 123456.789; // German uses comma as decimal separator and period for thousands console.log(new Intl.NumberFormat("de-DE").format(number)); // 123.456,789 // Arabic in most Arabic speaking countries uses real Arabic digits console.log(new Intl.NumberFormat("ar-EG").format(number)); // ١٢٣٤٥٦٫٧٨٩ // India uses thousands/lakh/crore separators console.log(new Intl.NumberFormat("en-IN").format(number)); // 1,23,456.789 // the nu extension key requests a numbering system, e.g.
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Number › toLocaleString
Number.prototype.toLocaleString() - JavaScript | MDN
const number = 123456.789; // German uses comma as decimal separator and period for thousands console.log(number.toLocaleString("de-DE")); // 123.456,789 // Arabic in most Arabic speaking countries uses Eastern Arabic digits console.log(number.toLocaleString("ar-EG")); // ١٢٣٤٥٦٫٧٨٩ // India uses thousands/lakh/crore separators console.log(number.toLocaleString("en-IN")); // 1,23,456.789 // the nu extension key requests a numbering system, e.g.
Find elsewhere
🌐
Reddit
reddit.com › r/webdev › what is the best way to handle a period or comma as a thousand or decimal separator in web applications?
r/webdev on Reddit: What is the best way to handle a period or comma as a thousand or decimal separator in web applications?
August 8, 2023 -

During the period in which I develop fullstack applications, this is exactly what caused me the most problems. And here I am, developing a budget app for expense management - both, a web app and a mobile app, and of course I have problems with these things.

The problem is that it seems to me that there is no universal solution that all browsers and operating systems adhere to.

Even countries do not have a common solution. Europe primarily uses a comma as a decimal separator, and a dot as a thousand separator. in America and Canada it is the other way around, and some countries, such as Switzerland also uses an apostrophe (') as a thousand separator.

Top answer
1 of 16
3955

I used the idea from Kerry's answer, but I 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 two 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.

2 of 16
3275

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.

🌐
DataTables
datatables.net › examples › i18n › comma-decimal.html
DataTables example - Language - Comma decimal place
A dot (.) is used to mark the decimal place in JavaScript, however, many parts of the world use a comma (,) and other characters such as the Unicode decimal separator (⎖) or a dash (-) are often used to show the decimal place in a displayed number.
🌐
David Berri
dberri.com › formatting-numbers-in-javascript
Formatting numbers in JavaScript
November 3, 2021 - So, when I say we are going to ... Brazil we the most common way to represent numbers is like so: 1.234.567,89. The comma is the decimal separator and the period is the thousands separators....
🌐
GitHub
github.com › josdejong › mathjs › issues › 421
Number format, decimal separator / delimiter other than '.' · Issue #421 · josdejong/mathjs
August 6, 2015 - Number format, decimal separator / delimiter other than '.'#421 · Copy link · darklajid · opened · on Aug 6, 2015 · Issue body actions · I know that JS is to blame, but maybe it would be worth looking into this - depending on the architecture of the parser stages it might be possible to 'fix' this in math.js?
Author   darklajid
🌐
Retool
community.retool.com › 💬 feature requests
Comma as number separator - 💬 Feature Requests - Retool Forum
August 24, 2023 - A request to be able to change the decimal separator to a comma and thousands separator to a dot. This should be set per organisation or should follow the browser localization settings. In Europe (and a lot of other cou…
🌐
Reddit
reddit.com › r/react › how do you handle number inputs for germany and other comma-based decimal separator countries?
r/react on Reddit: How do you handle number inputs for Germany and other comma-based decimal separator countries?
September 14, 2023 -

Hey everyone,

I use the standard HTML input element with input mode as "numeric". Some of my German customers have been complaining about not being able to enter decimal numbers. It might be apparent to some of you but some countries use the comma "," as the decimal separator.

German example:

1.222.333,44 → 1222333.44 (desired outcome to be written into the system)

Other countries:

1,222,333.44 → 1222333.44 (desired outcome to be written into the system)

I assume many countries use the comma "," as the decimal separator. What's the best way to handle this?

🌐
TutorialsPoint
tutorialspoint.com › article › How-to-print-a-number-with-commas-as-thousands-of-separators-in-JavaScript
How to print a number with commas as thousands of separators in JavaScript?
October 20, 2022 - Check for the decimal point and number sign. Remove the sign, loop through, and add commas to 3 digits group accordingly. Add the sign back and display the output. Here, the negative floating point input is processed by the custom code based ...
🌐
Tales from the Evil Empire
weblogs.asp.net › jdanforth › jquery-validate-and-the-comma-decimal-separator
Dev Blog - Johan Danforth - jQuery validate and the comma decimal separator
If you live outside the US and have problems with getting client side validation accepting comma decimal separator in input fields - just overwrite jQuery validation range and number methods with these javascript lines in the end of all your javascript loading.
Top answer
1 of 3
24

According to the specification, a DecimalLiteral is defined as:

DecimalLiteral ::
    DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt 
    . DecimalDigits ExponentPartopt 
    DecimalIntegerLiteral ExponentPartopt

and for satisfying the parseFloat argument:

  1. Let inputString be ToString(string).
  2. Let trimmedString be a substring of inputString consisting of the leftmost character that is not a StrWhiteSpaceChar and all characters to the right of that character.(In other words, remove leading white space.)
  3. If neither trimmedString nor any prefix of trimmedString satisfies the syntax of a StrDecimalLiteral (see 9.3.1), return NaN.
  4. Let numberString be the longest prefix of trimmedString, which might be trimmedString itself, that satisfies the syntax of a StrDecimalLiteral.
  5. Return the Number value for the MV

So numberString becomes the longest prefix of trimmedString that satisfies the syntax of a StrDecimalLiteral, meaning the first parseable literal string number it finds in the input. Only the . can be used to specify a floating-point number. If you're accepting inputs from different locales, use a string replace:

function parseLocalNum(num) {
    return +(num.replace(",", "."));
}

The function uses the unary operator instead of parseFloat because it seems to me that you want to be strict about the input. parseFloat("1ABC") would be 1, whereas using the unary operator +"1ABC" returns NaN. This makes it MUCH easier to validate the input. Using parseFloat is just guessing that the input is in the correct format.

2 of 3
15

use:

theNumber.toLocaleString();

to get a properly formatted string with the right decimal and thousands separators