如何格式化数字?

191

我想使用JavaScript格式化数字。

例如:

10     => 10.00
100    => 100.00
1000   => 1,000.00
10000  => 10,000.00
100000 => 100,000.00

12
你确定是指“1,00,000”吗?也许是“100,000”。 - Lightness Races in Orbit
13
有趣的事实 - 在印度,他们把数字分成组,比如12,34,567.89。 - Nils
5
(1234567.89).toLocaleString('hi-IN') 的翻译是 "12,34,567.89"。 - Michael
一行代码:Intl.NumberFormat().format(2500) 参见参考文献 - Ricardo
17个回答

303

如果你想使用内置代码,你可以使用 toLocaleString()minimumFractionDigits

扩展选项的浏览器兼容性 在我回答这个问题时很有限,但目前的状态看起来不错。如果你正在使用Node.js, 你需要npm install intl 包。

var value = (100000).toLocaleString(
  undefined, // leave undefined to use the visitor's browser 
             // locale or a string like 'en-US' to override it.
  { minimumFractionDigits: 2 }
);
console.log(value);

数字格式在不同文化之间有所区别。除非您要对输出进行字符串比较,否则礼貌的做法是选择“undefined”,让访问者的浏览器使用他们最熟悉的格式。2

// Demonstrate selected international locales
var locales = [
  undefined,  // Your own browser
  'en-US',    // United States
  'de-DE',    // Germany
  'ru-RU',    // Russia
  'hi-IN',    // India
  'de-CH',    // Switzerland
];
var n = 100000;
var opts = { minimumFractionDigits: 2 };
for (var i = 0; i < locales.length; i++) {
  console.log(locales[i], n.toLocaleString(locales[i], opts));
}

如果您来自具有不同格式的文化,请编辑此帖并添加您的语言区域代码。


1 你不应该这样做。
2 当然,除非你已经转换成当地汇率,否则不要使用此用于货币{style:'currency',currency:'JPY'}之类的东西。您不想让您的网站告诉人们价格是¥300,而实际上是$300。有时真正的电子商务网站会犯这个错误。


1
我想使用内置代码,这让我成功了。locales选项是一个小问题,但我愿意接受它。我认为这应该是被接受的答案,因为它考虑了数字呈现的语言环境细微差别。 - Alexander Dixon
2
请注意:toLocaleString在Node中速度非常慢,且可能会导致内存泄漏!这是在Node 10.16.3上测试的结果:const number = Math.random() * 10; const params = { minimumFractionDigits: 3, maximumFractionDigits: 3, useGrouping: false }; for (let i = 0; i < 100000; i++) { Number(number).toLocaleString('en-US', params); } console.log('on end RSS = ', process.memoryUsage().rss / 1024 / 1024); - Dmitriy T

60

使用

num = num.toFixed(2);

这里的“2”表示小数点后的位数。

编辑:

以下是将数字格式化为所需格式的函数。

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

Sorce: www.mredkj.com


3
使用.toFixed(2)将无法得到10000和100000的结果为10,000.00和1,00,000.00。 - Kanak Vaghela
1
简单而快速!这需要是最好的答案! - Weslley Rufino de Lima
为了更容易理解,我更改了变量的名称。function formatNumber(number) { number= number.toFixed(2); brokenNumbersPostPoint= number.split('.'); numbersBeforePoint= brokenNumbersPostPoint[0]; numbersAfterPoint= brokenNumbersPostPoint.length > 1 ? '.' + brokenNumbersPostPoint[1] : '';var rgx = /(\d+)(\d{3})/; while (rgx.test(numbersBeforePoint)) { numbersBeforePoint= numbersBeforePoint.replace(rgx, '$1' + ',' + '$2'); } return numbersBeforePoint+ numbersAfterPoint;} - Weslley Rufino de Lima

58

简短解决方案:

var n = 1234567890;
String(n).replace(/(.)(?=(\d{3})+$)/g,'$1,')
// "1,234,567,890"

50

所有非废弃的浏览器(甚至一些已过时的浏览器)现在都支持 ECMAScript® 国际化 API 规范 (ECMA-402),它提供了Intl.NumberFormat。你可以用它来实现这个功能:

const nFormat = new Intl.NumberFormat();
const count = 42000000;
console.log(nFormat.format(count)); // 42,000,000 in many locales, 42.000.000 in many other locales

if (typeof Intl === "undefined" || !Intl.NumberFormat) {
    console.log("This browser doesn't support Intl.NumberFormat");
} else {
    const nFormat = new Intl.NumberFormat();
    const count = 42000000;
    console.log(nFormat.format(count)); // 42,000,000 in many locales, 42.000.000 in many other locales
}


我认为这是最简单的解决方案。 - Tech

28

鉴于JasperV发现的错误——很好的提点!——我已经重写了我的旧代码。我想我只曾用过这个正值且保留两位小数。

根据您尝试实现的内容,您可能需要四舍五入或不需要,因此这里将其分为两个版本。

首先是带有四舍五入的版本。

我引入了toFixed()方法,它更好地处理了精确舍入到特定小数位,并且得到了很好的支持。它确实会减慢事情的速度。

此版本仍然分离小数,但使用了与之前不同的方法。 w|0部分删除小数。关于此的更多信息,请参见good answer。然后留下剩余的整数,将其存储在k中,然后再从原始数字中减去它,使小数单独留下。

此外,如果我们考虑负数,我们需要while循环(跳过三个数字),直到达到b。当处理负数时,这已计算为1,以避免出现类似-,100.00的东西

循环的其余部分与之前相同。

function formatThousandsWithRounding(n, dp){
  var w = n.toFixed(dp), k = w|0, b = n < 0 ? 1 : 0,
      u = Math.abs(w-k), d = (''+u.toFixed(dp)).substr(2, dp),
      s = ''+k, i = s.length, r = '';
  while ( (i-=3) > b ) { r = ',' + s.substr(i, 3) + r; }
  return s.substr(0, i + 3) + r + (d ? '.'+d: '');
};

在下面的片段中,您可以编辑数字以进行测试。

function formatThousandsWithRounding(n, dp){
  var w = n.toFixed(dp), k = w|0, b = n < 0 ? 1 : 0,
      u = Math.abs(w-k), d = (''+u.toFixed(dp)).substr(2, dp),
      s = ''+k, i = s.length, r = '';
  while ( (i-=3) > b ) { r = ',' + s.substr(i, 3) + r; }
  return s.substr(0, i + 3) + r + (d ? '.'+d: '');
};

var dp;
var createInput = function(v){
  var inp = jQuery('<input class="input" />').val(v);
  var eql = jQuery('<span>&nbsp;=&nbsp;</span>');
  var out = jQuery('<div class="output" />').css('display', 'inline-block');
  var row = jQuery('<div class="row" />');
  row.append(inp).append(eql).append(out);
  inp.keyup(function(){
    out.text(formatThousandsWithRounding(Number(inp.val()), Number(dp.val())));
  });
  inp.keyup();
  jQuery('body').append(row);
  return inp;
};

jQuery(function(){
  var numbers = [
    0, 99.999, -1000, -1000000, 1000000.42, -1000000.57, -1000000.999
  ], inputs = $();
  dp = jQuery('#dp');
  for ( var i=0; i<numbers.length; i++ ) {
    inputs = inputs.add(createInput(numbers[i]));
  }
  dp.on('input change', function(){
    inputs.keyup();
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="dp" type="range" min="0" max="5" step="1" value="2" title="number of decimal places?" />

另一种无需舍入的版本。

这种方法避免了数学计算(因为这可能引入舍入或舍入误差)。如果您不想进行舍入,则只需将其视为字符串,即1000.999转换为两个小数位将永远只是1000.99而不是1001.00。

此方法避免使用.split()RegExp(),两者相比非常慢。虽然我从Michael的答案中学到了有关toLocaleString的新知识,但我也惊讶地发现,它在所有方法中——至少在Firefox和Chrome; Mac OSX中——是最慢的。

使用lastIndexOf(),我们找到可能存在的小数点,然后其他事情基本相同。除了需要填充额外的0之外。此代码仅限于5个小数位。根据我的测试,这是更快的方法。

var formatThousandsNoRounding = function(n, dp){
  var e = '', s = e+n, l = s.length, b = n < 0 ? 1 : 0,
      i = s.lastIndexOf('.'), j = i == -1 ? l : i,
      r = e, d = s.substr(j+1, dp);
  while ( (j-=3) > b ) { r = ',' + s.substr(j, 3) + r; }
  return s.substr(0, j + 3) + r + 
    (dp ? '.' + d + ( d.length < dp ? 
        ('00000').substr(0, dp - d.length):e):e);
};

var formatThousandsNoRounding = function(n, dp){
  var e = '', s = e+n, l = s.length, b = n < 0 ? 1 : 0,
      i = s.lastIndexOf('.'), j = i == -1 ? l : i,
      r = e, d = s.substr(j+1, dp);
  while ( (j-=3) > b ) { r = ',' + s.substr(j, 3) + r; }
  return s.substr(0, j + 3) + r + 
   (dp ? '.' + d + ( d.length < dp ? 
     ('00000').substr(0, dp - d.length):e):e);
};

var dp;
var createInput = function(v){
  var inp = jQuery('<input class="input" />').val(v);
  var eql = jQuery('<span>&nbsp;=&nbsp;</span>');
  var out = jQuery('<div class="output" />').css('display', 'inline-block');
  var row = jQuery('<div class="row" />');
  row.append(inp).append(eql).append(out);
  inp.keyup(function(){
    out.text(formatThousandsNoRounding(Number(inp.val()), Number(dp.val())));
  });
  inp.keyup();
  jQuery('body').append(row);
  return inp;
};

jQuery(function(){
  var numbers = [
    0, 99.999, -1000, -1000000, 1000000.42, -1000000.57, -1000000.999
  ], inputs = $();
  dp = jQuery('#dp');
  for ( var i=0; i<numbers.length; i++ ) {
    inputs = inputs.add(createInput(numbers[i]));
  }
  dp.on('input change', function(){
    inputs.keyup();
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="dp" type="range" min="0" max="5" step="1" value="2" title="number of decimal places?" />

稍后我将更新一个页面内的示例演示,但现在这里是一个 fiddle:

https://jsfiddle.net/bv2ort0a/2/



旧方法

为什么要使用 RegExp?- 在不需要用锤子时,不要使用牙签即可,即使用字符串操作:

var formatThousands = function(n, dp){
  var s = ''+(Math.floor(n)), d = n % 1, i = s.length, r = '';
  while ( (i -= 3) > 0 ) { r = ',' + s.substr(i, 3) + r; }
  return s.substr(0, i + 3) + r + 
    (d ? '.' + Math.round(d * Math.pow(10, dp || 2)) : '');
};

操作指南

formatThousands( 1000000.42 );

首先去掉小数部分:

s = '1000000', d = ~ 0.42

从字符串末尾开始反向处理:

',' + '000'
',' + '000' + ',000'

加上剩余的前缀和小数后缀(四舍五入到小数点后dp位)即可完成:

'1' + ',000,000' + '.42'

fiddlesticks

http://jsfiddle.net/XC3sS/


4
这个程序有两个bug: 当使用负数时,会在小数点处出错:-1000000.42变成-1,000,001.-42,并且由于使用了floor方法导致结果添加了一个1。另外还存在另一个小数错误:当使用 dp=2 处理 1000000.999 时,结果为 1,000,000.100,即有3位小数,但是我的数字没有被四舍五入。 - JasperV
3
@JasperV,非常好的观点......感谢您提出警告。在之前的任何使用情况中都没有发现这些问题。但现在应该已经解决了。 - Pebbl

10

使用toFixed函数和该函数来添加逗号。

function addCommas(nStr)
{
    nStr += '';
    var x = nStr.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;
}
n = 10000;
r = n.toFixed(2); //10000.00

addCommas(r); // 10,000.00

http://www.mredkj.com/javascript/numberFormat.html


但是使用.toFixed(2)将无法得到10000和100000的结果,如10,000.00和1,00,000.00。 - Kanak Vaghela
4
如果你从其他地方复制代码,提供参考链接会很好:http://www.mredkj.com/javascript/numberFormat.html - oezi
@oezi - 当然,没问题。@Chris - 已更新以显示逗号格式。 - John Giotta
感谢您的回答 :) - dada

7

您可能希望考虑使用toLocaleString()

示例:

const number = 1234567890.123;

console.log(number.toLocaleString('en-US')); // US format

console.log(number.toLocaleString('en-IN')); // Indian format

在Chrome v60和v88中进行测试。

来源:Number.prototype.toLocaleString() | MDN


2
这是不正确的。限制(有效)数字的数量来自于将选项对象提供给.toLocaleString(locale_id, options)方法。像这样:toLocaleString(ANY_LOCALE_ID, { maximumSignificantDigits: 3 }) - Youp Bernoulli
2
@BernoulliIT,感谢您提出这个问题,我已经更新了我的答案。 - Rahul Desai
我没有看到答案的修正更新!这个答案绝对是最直接和优雅的解决方案,可以回答OP的问题。 - Youp Bernoulli
@BernoulliIT,您所说的“没有看到答案的修正更新”是什么意思?您尝试清除浏览器缓存了吗? - Rahul Desai
你说得对,我原本以为OP的问题是关于限制数字位数的(这也是我在找到这篇帖子时所寻找的),但实际上并非如此。我的想法有些混淆了。 - Youp Bernoulli

5
我认为使用这个jQuery-numberformatter插件可以解决你的问题。
当然,前提是你的项目使用了jQuery库。请注意,该功能与blur事件绑定。

$("#salary").blur(function(){
      $(this).parseNumber({format:"#,###.00", locale:"us"});
      $(this).formatNumber({format:"#,###.00", locale:"us"});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<script src="https://cdn.jsdelivr.net/gh/timdown/jshashtable/hashtable.js"></script>

<script src="https://cdn.jsdelivr.net/gh/hardhub/jquery-numberformatter/src/jquery.numberformatter.js"></script>

<input type="text" id="salary">


1
Google Code于2016年1月15日关闭(详情请见https://opensource.googleblog.com/2015/03/farewell-to-google-code.html)。您可能需要更新无法访问的链接,即“404. That's an error.”(许多Google Code上的项目已经迁移到GitHub,请参考http://en.wikipedia.org/wiki/GitHub)。 - Peter Mortensen
谢谢@PeterMortensen!链接已更新! - Cacho Santa
为什么要踩我?能解释一下吗? - Cacho Santa
更新了代码片段,使查看结果和脚本更加简单。 - Cacho Santa

4

这篇文章是关于您的问题的。在JavaScript中没有内置千位分隔符,因此您需要编写自己的函数,例如下面的示例(取自链接页面):

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

4

function numberWithCommas(x) {
  x=String(x).toString();
  var afterPoint = '';
  if(x.indexOf('.') > 0)
     afterPoint = x.substring(x.indexOf('.'),x.length);
  x = Math.floor(x);
  x=x.toString();
  var lastThree = x.substring(x.length-3);
  var otherNumbers = x.substring(0,x.length-3);
  if(otherNumbers != '')
      lastThree = ',' + lastThree;
  return otherNumbers.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + lastThree + afterPoint;
}

console.log(numberWithCommas(100000));
console.log(numberWithCommas(10000000));

输出

100,000
10,000,000


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接