Regular Expression for formatting numbers in JavaScript

JavascriptRegexFormatting

Javascript Problem Overview


I need to display a formatted number on a web page using JavaScript. I want to format it so that there are commas in the right places. How would I do this with a regular expression? I've gotten as far as something like this:

myString = myString.replace(/^(\d{3})*$/g, "${1},");

...and then realized this would be more complex than I think (and the regex above is not even close to what I need). I've done some searching and I'm having a hard time finding something that works for this.

Basically, I want these results:

  • 45 becomes 45
  • 3856 becomes 3,856
  • 398868483992 becomes 398,868,483,992

...you get the idea.

Javascript Solutions


Solution 1 - Javascript

This can be done in a single regex, no iteration required. If your browser supports ECMAScript 2018, you could simply use lookaround and just insert commas at the right places:

Search for (?<=\d)(?=(\d\d\d)+(?!\d)) and replace all with ,

In older versions, JavaScript doesn't support lookbehind, so that doesn't work. Fortunately, we only need to change a little bit:

Search for (\d)(?=(\d\d\d)+(?!\d)) and replace all with \1,

So, in JavaScript, that would look like:

result = subject.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");

Explanation: Assert that from the current position in the string onwards, it is possible to match digits in multiples of three, and that there is a digit left of the current position.

This will also work with decimals (123456.78) as long as there aren't too many digits "to the right of the dot" (otherwise you get 123,456.789,012).

You can also define it in a Number prototype, as follows:

Number.prototype.format = function(){
   return this.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
};

And then using it like this:

var num = 1234;
alert(num.format());

Credit: Jeffrey Friedl, Mastering Regular Expressions, 3rd. edition, p. 66-67

Solution 2 - Javascript

Formatting a number can be handled elegantly with one line of code.

This code extends the Number object; usage examples are included below.

Code:

Number.prototype.format = function () {
    return this.toString().split( /(?=(?:\d{3})+(?:\.|$))/g ).join( "," );
};

How it works

The regular expression uses a look-ahead to find positions within the string where the only thing to the right of it is one or more groupings of three numbers, until either a decimal or the end of string is encountered. The .split() is used to break the string at those points into array elements, and then the .join() merges those elements back into a string, separated by commas.

The concept of finding positions within the string, rather than matching actual characters, is important in order to split the string without removing any characters.

Usage examples:

var n = 9817236578964235;
alert( n.format() );    // Displays "9,817,236,578,964,235"

n = 87345.87;
alert( n.format() );    // Displays "87,345.87"

Of course, the code can easily be extended or changed to handle locale considerations. For example, here is a new version of the code that automatically detects the locale settings and swaps the use of commas and periods.

Locale-aware version:

Number.prototype.format = function () {

    if ((1.1).toLocaleString().indexOf(".") >= 0) {
        return this.toString().split( /(?=(?:\d{3})+(?:\.|$))/g ).join( "," );
    }
    else {
        return this.toString().split( /(?=(?:\d{3})+(?:,|$))/g ).join( "." );
    }
};

Unless it's really necessary, I prefer the simplicity of the first version though.

Solution 3 - Javascript

With the caveat that Intl.NumberFormat and Number.toLocaleString() are now there for this purpose in JavaScript:

The other answers using regular expressions all break down for decimal numbers (although the authors seem to not know this because they have only tested with 1 or 2 decimal places). This is because without lookbehind, JS regular expressions have no way to know whether you are working with the block of digits before or after the decimal point. That leaves two ways to address this with JS regular expressions:

  1. Know whether there is a decimal point in the number, and use different regular expressions depending on that:
  • /(\d)(?=(\d{3})+$)/g for integers
  • /(\d)(?=(\d{3})+\.)/g for decimals
  1. Use two regular expressions, one to match the decimal portion, and a second to do a replace on it.

function format(num) {
  return num.toString().replace(/^[+-]?\d+/, function(int) {
    return int.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
  });
}

console.log(format(332432432))
console.log(format(332432432.3432432))
console.log(format(-332432432))
console.log(format(1E6))
console.log(format(1E-6))

Solution 4 - Javascript

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
var num=numberWithCommas(2000000); //any number
console.log(num);

enter code here

Try this

Solution 5 - Javascript

// You might want to take decimals into account

Number.prototype.commas= function(){
 var s= '', temp, 
 num= this.toString().split('.'), n=num[0];
 while(n.length> 3){
  temp= n.substring(n.length-3);
  s= ','+temp+s;
  n= n.slice(0, -3);
 }
 if(n) s= n+s;
 if(num[1]) s+='.'+num[1];
 return s;
}

var n= 10000000000.34;

n.commas() = returned value: (String) 10,000,000,000.34

Solution 6 - Javascript

underscore.string has a nice implementation.

I've amended it slightly to accept numeric strings.

function numberFormat(number, dec, dsep, tsep) {
  if (isNaN(number) || number == null) return '';

  number = parseFloat(number).toFixed(~~dec);
  tsep = typeof tsep == 'string' ? tsep : ',';

  var parts = number.split('.'),
    fnums = parts[0],
    decimals = parts[1] ? (dsep || '.') + parts[1] : '';

  return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
}

console.log(numberFormat(123456789))
console.log(numberFormat(123456789.123456789))
console.log(numberFormat(-123456789))
console.log(numberFormat(1E6))
console.log(numberFormat(1E-6))
console.log('---')
console.log(numberFormat(123456789, 6, ',', '_'))
console.log(numberFormat(123456789.123456789, 6, ',', '_'))
console.log(numberFormat(-123456789, 6, ',', '_'))
console.log(numberFormat(1E6, 6, ',', '_'))
console.log(numberFormat(1E-6, 6, ',', '_'))

Solution 7 - Javascript

Try something like this:

function add_commas(numStr)
{
	numStr += '';
	var x = numStr.split('.');
	var x1 = x[0];
	var x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

Solution 8 - Javascript

If you really want a regex, you can use two in a while loop:

while(num.match(/\d{4}/)) {
	num = num.replace(/(\d{3})(,\d|$)/, ',$1$2');
}

And if you want to be fancy, you can format numbers with decimal points too:

while(num.match(/\d{4}(\,|\.)/)) {
	num = num.replace(/(\d{3})(,\d|$|\.)/, ',$1$2');
}

Edit:

You can also do this with 2 regular expressions and no loop, splits, joins, etc:

num = num.replace(/(\d{1,2}?)((\d{3})+)$/, "$1,$2");
num = num.replace(/(\d{3})(?=\d)/g, "$1,");

The first regex puts a comma after the first 1 or 2 digits if the remaining number of digits is divisible by three. The second regex places a comma after every remaining group of 3 digits.

These won't work with decimals, but they work great for positive and negative integers.

Test output:

45
3,856
398,868,483,992

635
12,358,717,859,918,856
-1,388,488,184

Solution 9 - Javascript

Someone mentioned that lookbehind isn't possible in Javascript RegExp. Here is a great page that explains how to use lookaround (lookahead and lookbehind).

http://www.regular-expressions.info/lookaround.html

Solution 10 - Javascript

One RegExp for integers and decimals:

// Formats number 1234.5678 into string "1 234.5678".
function formatNumber(number: number): string {
    return number.toString().replace(/(?<!(\.\d*|^.{0}))(?=(\d{3})+(?!\d))/g, ' ');
}

console.log(formatNumber(1234.5678)); // "1 234.5678"
console.log(formatNumber(123)); // "123"
console.log(formatNumber(123.45678)); // "123.45678"
console.log(formatNumber(123456789.11111111)); // "123 456 789.1111111"

Solution 11 - Javascript

I think you would necessarily have to do multiple passes to achieve this with regular expressions. Try the following:

  1. Run a regex for one digit followed by 3 digits.
  2. If that regex matches, replace it with the first digit, then a comma, then the next 3 digits.
  3. Repeat until (1) finds no matches.

Solution 12 - Javascript

First reverse a character array, then add commas after every third number unless it's just before the end of the string or before a - sign. Then reverse the character array again and make it a string again.

function add_commas(numStr){
    return numStr.split('').reverse().join('').replace(/(\d{3})(?=[^$|^-])/g, "$1,").split('').reverse().join('');
}

Solution 13 - Javascript

Iteration isn't necessary

function formatNumber(n, separator) {
    separator = separator || ",";

    n = n.toString()
        .split("").reverse().join("")
        .replace(/(\d{3})/g, "$1" + separator)
        .split("").reverse().join("");

    // Strings that have a length that is a multiple of 3 will have a leading separator
    return n[0] == separator ? n.substr(1) : n;
}

var testCases = [1, 45, 2856, 398868483992];
for ( var i in testCases ) {
    if ( !ns.hasOwnProperty(i) ) { continue; }
    console.info(testCases[i]);   
    console.log(formatNumber(testCases[i]));
}

Results

1
1

45
45

2856
2,856

398868483992
398,868,483,992

Solution 14 - Javascript

Brandon,

I didn't see too many answers working the regex from the decimal point back, so I thought I might chime in.

I wondered if there is any elegant benefit to re-writing the regexp to scan from the back forward...

function addCommas(inputText) {
    // pattern works from right to left
	var commaPattern = /(\d+)(\d{3})(\.\d*)*$/;
	var callback = function (match, p1, p2, p3) {
		return p1.replace(commaPattern, callback) + ',' + p2 + (p3 || '');
	};
	return inputText.replace(commaPattern, callback);
}

>> Fiddle Demo <<

This accounts for any decimal place.

Solution 15 - Javascript

After so much searching, I generate a regex which accepts all formats

(\d+[-, ,(]{0,3}\d+[-, ,(,)]{0,3}\d+[-, ,(,)]{0,3}\d+[)]{0,2})

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
QuestionBrandon MontgomeryView Question on Stackoverflow
Solution 1 - JavascriptTim PietzckerView Answer on Stackoverflow
Solution 2 - JavascriptSpeednetView Answer on Stackoverflow
Solution 3 - JavascriptAdam LeggettView Answer on Stackoverflow
Solution 4 - JavascriptRafiView Answer on Stackoverflow
Solution 5 - JavascriptkennebecView Answer on Stackoverflow
Solution 6 - JavascriptmpenView Answer on Stackoverflow
Solution 7 - JavascriptSethView Answer on Stackoverflow
Solution 8 - JavascriptJeff BView Answer on Stackoverflow
Solution 9 - JavascriptRobustoView Answer on Stackoverflow
Solution 10 - JavascriptSIARHEI PAKHUTAView Answer on Stackoverflow
Solution 11 - JavascriptRyan BrunnerView Answer on Stackoverflow
Solution 12 - JavascriptHarmenView Answer on Stackoverflow
Solution 13 - JavascriptJustin JohnsonView Answer on Stackoverflow
Solution 14 - JavascriptLevi BeckmanView Answer on Stackoverflow
Solution 15 - JavascriptBijendra SinghView Answer on Stackoverflow