如何在JavaScript中以逗号将数字打印为千位分隔符


1779

我正在尝试在JavaScript中使用逗号将整数打印为数千个分隔符。例如,我想将数字1234567显示为“ 1,234,567”。我将如何去做呢?

这是我的做法:

function numberWithCommas(x) {
    x = x.toString();
    var pattern = /(-?\d+)(\d{3})/;
    while (pattern.test(x))
        x = x.replace(pattern, "$1,$2");
    return x;
}

有更简单或更优雅的方法吗?如果它也可以与浮点数一起使用,那就太好了,但这不是必需的。在句点和逗号之间进行决定不需要特定于区域设置。


156
Number(x).toLocaleString()
Boffin

@Boffin对于输入类型号不起作用(由于逗号)-在接受的答案中,我们可以将逗号替换为点,并且输入类型号将起作用
Vitaly Zdanevich

48
值得注意的是,在2016年Safari 中Number.prototype.toLocaleString 仍然无法使用。而不是实际格式化数字,它只是返回它,不会引发任何错误。由于这个原因,今天拥有最大的面部

但是,它似乎确实可以在iOS Safari中使用。
蒂姆(Tim)

toLocaleString不一致,不应使用。例如-在Firefox这将返回1,234,但在IE浏览器,这将增加小数:1,234.00
BORT

Answers:


2828

我使用了Kerry的回答中的想法,但是由于我只是为了自己的特定目的寻找简单的东西,所以简化了它。这是我所做的:

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}


正则表达式使用2个超前断言:

  • 一个正值,用于查找字符串中连续有3个数字的倍数的任何点,
  • 否定断言,以确保该点仅具有3位数的整数倍。替换表达式在此处放置逗号。

例如,如果传递它123456789.01,则肯定断言将匹配7左边的每个点(因为它789是3位数678的倍数,是3位数的倍数,依此567类推)。否定断言检查3位数的倍数后是否没有任何数字。789在其后有一个句点,因此它恰好是3位数的倍数,因此逗号在此处。678是3位数的倍数,但是9后面有一个数字,因此这3位数是4位数的一部分,并且逗号不在该位置。同样适用于567456789是6位数字,是3的倍数,因此在此之前加逗号。345678是3的倍数,但是9后面有一个后缀,所以那里没有逗号。等等。的\B 防止正则表达式在字符串的开头放置逗号。

@ neu-rah提到如果小数点后有3位以上的数字,则此函数在不希望出现的位置添加逗号。如果有问题,可以使用此功能:

function numberWithCommas(x) {
    var parts = x.toString().split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
}

@ tjcrowder指出,现在JavaScript已经落后了(支持信息),可以在正则表达式本身中解决它:

function numberWithCommas(x) {
    return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}

(?<!\.\d*).后面有一个否定性的含义,表示匹配之前不能有零个或多个数字。至少在V8中,负向后看比splitand join解决方案(比较)要快。


21
很酷,确实注意到它的数字有问题,但是小数点后3位以上。
埃里克·彼得罗里耶

60
试试numberWithCommas(12345.6789)->“ 12,345.6,789”我不喜欢
neu-rah

4
它不以分数很好地工作,我们不希望在小数点后有逗号
梦幻

30
在'。'之后修复的小改进。问题'123456789.01234'.replace(/ \ B(?=(?= \ d * \。)(\ d {3})+(?!\ d))/ g,'_')
Dmitrij Golubev

8
@DmitrijGolubev不适用于整数。也许强迫小数点是解决方案。
弗拉德(Vlad)2015年

1807

我很惊讶没有人提到Number.prototype.toLocaleString。它是在JavaScript 1.5(于1999年推出)中实现的,因此基本上所有主流浏览器都支持它。

var n = 34523453.345
n.toLocaleString()
"34,523,453.345"

通过包含Intl,它也可以从v0.12版本开始在Node.js中工作。

请注意,此函数返回的是字符串,而不是数字。

如果您想要不同的东西,Numeral.js可能会很有趣。


17
@csigrist好点了,但是还没有看起来那么糟糕。速度取决于浏览器。在FF或Opera中,它表现良好。虽然我很讨厌Chrome。至于零:var number = 123456.000; number.toLocaleString('en-US', {minimumFractionDigits: 2}); "123,456.00"这些选项在FF或Safari中不起作用。
uKolka

22
取决于上下文,性能差异可能是问题,也可能不是问题。如果将其用于包含1000个结果的巨型表中,则将更为重要,但如果仅用于单个值,则差异可忽略不计。但是优点是它可以感知区域设置,因此欧洲的某人会看到34.523.453,34534523453453345。对于来自许多国家/地区的访问者来说,这一点更为重要。
T Nguyen

6
太棒了 最后是具有本机功能的答案。而且,此代码可以在不同的国家/地区使用不同的分隔符正确显示(我们在捷克共和国写X XXX XXX,YYY)。
托马什Zato -恢复莫妮卡

22
googlers更新:toLocaleString通过包含Intl在v0.12以及更高版本的Node.js中工作。
srobinson

8
@MSC,您应该尝试parseInt("1234567", 10).toLocaleString('en-US', {minimumFractionDigits: 2})还是new Number("1234567").toLocaleString('en-US', {minimumFractionDigits: 2})代替。它不起作用,因为您在字符串而不是数字上使用它。
uKolka '16

244
var number = 1234567890; // Example number to be converted

⚠记住javascript的最大整数值为9007199254740991


toLocaleString

number.toLocaleString(); // "1,234,567,890"

// A more complex example: 
var number2 = 1234.56789; // floating point example
number2.toLocaleString(undefined, {maximumFractionDigits:2}) // "1,234.57"


NumberFormat(不支持 Safari):

var nf = new Intl.NumberFormat();
nf.format(number); // "1,234,567,890"

根据我的检查(至少是Firefox),它们在性能上或多或少都相同。


6
Safari上不支持NumberFormat,对于正在其中实现的任何人。
marcovega

6
Safari也不支持toLocaleString
Deepak Banka'Feb 1''1

3
我链接到的每个MDN页面的底部总是提到浏览器支持。
vsync

5
toLocaleString野生动物园的基本作品,请勿选择
dandavis

3
toLocaleString解决方案应该可能还包括所需的语言环境,所以toLocaleString("en"),因为英国模式使用逗号。但是,如果toLocaleString()没有在法国运行的语言环境指示器,那么它将产生句点而不是逗号,因为这是用来在本地分隔成千上万个字符的原因。
Mike'Pomax'Kamermans

112

我建议使用phpjs.org的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);
}

更新02/13/14

人们一直在报告这不能按预期工作,所以我做了一个包含自动测试的JS Fiddle

更新26/11/2017

这是作为堆栈片段的小提琴,其输出略有修改:

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;
}


并不是我把它记下来,但我相信人们这样做是因为它不起作用。就目前而言,我什至发现您的某些测试也不起作用。
安德鲁·S

3
@Andrew S-只有1个人将其标记为下。它确实有效,我已经在自己的代码中多次使用了它。它也不是我的代码(也不是我的测试),我引用了它来自的站点,这是一个著名的站点。也许他们有它的更新版本),因为您正在查看的代码已有3年的历史了。
凯里·琼斯

13
@ernix-操作员要求使用JavaScript,我给出的答案 JavaScript。这是PHP函数的JavaScript解释。
凯里·琼斯

2
@ernix-与OP给出的示例完全一样。我摆了一个小提琴,这样你就可以看到。
凯里·琼斯

4
@ernix-好的,但要点是它完全符合OP的要求。它来自另一个站点(不是我维护的,我之前已经声明过),并且在给它适当的变量时,它的工作原理与所述完全相同。如果您认为这是一个错误,请联系phpjs.org或查看他们是否具有更新版本。
凯里·琼斯

75

这是@ mikez302答案的一种变体,但已修改为支持带小数的数字(根据@ neu-rah的反馈,即numberWithCommas(12345.6789)->“ 12,345.6,789”而不是“ 12,345.6789”

function numberWithCommas(n) {
    var parts=n.toString().split(".");
    return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}


67
function formatNumber (num) {
    return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
}

print(formatNumber(2665));      // 2,665
print(formatNumber(102665));    // 102,665
print(formatNumber(111102665)); // 111,102,665

我的答案没有做什么?正则表达式看起来略有不同,但是看起来它应该做同样的事情。
伊利亚斯·扎马里亚

8
它更短:)
Tutankhamen 2014年

4
真优雅 正是我想要的。
传统时间

4
来自blog.tompawlak.org/number-currency-formatting-javascript吗?已知问题:formatNumber(0.123456)= 0.123,456 JS中缺少向后看的特性,很难使用优雅的正则表达式对其进行修复。
弗拉德

1
123456789.123456789.toString()。replace(/(\ d)(?=(\ d {3})+ \。)/ g,'$ 1,')=>
123,456,789.12345679

53

使用正则表达式

function toCommas(value) {
    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
console.log(toCommas(123456789)); // 123,456,789

console.log(toCommas(1234567890)); // 1,234,567,890
console.log(toCommas(1234)); // 1,234

使用toLocaleString()

var number = 123456.789;

// request a currency format
console.log(number.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' }));
// → 123.456,79 €

// the Japanese yen doesn't use a minor unit
console.log(number.toLocaleString('ja-JP', { style: 'currency', currency: 'JPY' }))
// → ¥123,457

// limit to three significant digits
console.log(number.toLocaleString('en-IN', { maximumSignificantDigits: 3 }));
// → 1,23,000

引用MDN:Number.prototype.toLocaleString()

使用Intl.NumberFormat()

var number = 123456.789;

console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(number));
// expected output: "123.456,79 €"

// the Japanese yen doesn't use a minor unit
console.log(new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' }).format(number));
// expected output: "¥123,457"

// limit to three significant digits
console.log(new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(number));

// expected output: "1,23,000"

ref Intl.NumberFormat

此处演示

<script type="text/javascript">
  // Using Regular expression
  function toCommas(value) {
    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

  function commas() {
    var num1 = document.myform.number1.value;

    // Using Regular expression
    document.getElementById('result1').value = toCommas(parseInt(num1));
    // Using toLocaleString()

    document.getElementById('result2').value = parseInt(num1).toLocaleString('ja-JP', {
      style: 'currency',
      currency: 'JPY'
    });

    // Using Intl.NumberFormat()
    document.getElementById('result3').value = new Intl.NumberFormat('ja-JP', {
      style: 'currency',
      currency: 'JPY'
    }).format(num1);
  }
</script>
<FORM NAME="myform">
  <INPUT TYPE="text" NAME="number1" VALUE="123456789">
  <br>
  <INPUT TYPE="button" NAME="button" Value="=>" onClick="commas()">
  <br>Using Regular expression
  <br>
  <INPUT TYPE="text" ID="result1" NAME="result1" VALUE="">
  <br>Using toLocaleString()
  <br>
  <INPUT TYPE="text" ID="result2" NAME="result2" VALUE="">
  <br>Using Intl.NumberFormat()
  <br>
  <INPUT TYPE="text" ID="result3" NAME="result3" VALUE="">

</FORM>

性能

性能 http://jsben.ch/sifRd


如果您正在动态键入,则此方法不起作用。如果只给它一个值,它就可以工作,但是如果您不断动态地输入一个值,则逗号会被添加到错误的位置。
Edgar Quintero

我已经在答案下方更新了演示。在文本框中输入动态值时。你测试尝试@EdgarQuintero
静省午光

39

国际编号格式

原生JS功能。受IE11,Edge,最新的Safari,Chrome,Firefox,Opera,iOS上的Safari和Android上的Chrome支持。

var number = 3500;

console.log(new Intl.NumberFormat().format(number));
// → '3,500' if in US English locale

我的回答已根据您的评论进行了更新。谢谢!
达斯汀·孙

35

感谢大家的答复。我已经建立了一些答案,以制定一个“一刀切”的解决方案。

第一个片段添加功能模仿PHPnumber_format()到数字样机。如果我要格式化数字,则通常需要小数位,因此该函数需要显示小数位。某些国家/地区使用逗号作为小数点,使用小数点作为千位分隔符,因此该功能允许设置这些分隔符。

Number.prototype.numberFormat = function(decimals, dec_point, thousands_sep) {
    dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
    thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';

    var parts = this.toFixed(decimals).split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousands_sep);

    return parts.join(dec_point);
}

您将按以下方式使用它:

var foo = 5000;
console.log(foo.numberFormat(2)); // us format: 5,000.00
console.log(foo.numberFormat(2, ',', '.')); // european format: 5.000,00

我发现我经常需要取回数字以进行数学运算,但是parseFloat仅将整数值的第一个序列转换为5,000到5。因此,我创建了自己的float转换函数,并将其添加到String原型中。

String.prototype.getFloat = function(dec_point, thousands_sep) {
    dec_point = typeof dec_point !== 'undefined' ? dec_point : '.';
    thousands_sep = typeof thousands_sep !== 'undefined' ? thousands_sep : ',';

    var parts = this.split(dec_point);
    var re = new RegExp("[" + thousands_sep + "]");
    parts[0] = parts[0].replace(re, '');

    return parseFloat(parts.join(dec_point));
}

现在,您可以如下使用这两个功能:

var foo = 5000;
var fooString = foo.numberFormat(2); // The string 5,000.00
var fooFloat = fooString.getFloat(); // The number 5000;

console.log((fooString.getFloat() + 1).numberFormat(2)); // The string 5,001.00

2
很好,我借用了第一种方法;)但是,当您要使用欧洲格式并且数字是小数时,它不会产生正确的结果。第5行应为:var parts = this.toFixed(decimals).toString().split('.');
vbwx

你是对的!toFixed()将逗号更改为句点,因此“。” 应该代替var dec_point。感谢您指出了这一点。

您可以为此制作一个npm模块吗?
chovy

3
@ J.Money .toString是不必要的,toFixed已经返回了一个字符串。
Ariel 2014年

我不知道为什么你提到的PHP在这里的所有,或给予其已经是prototipical功能存在
VSYNC

27

这个问题得到的答案让我印象深刻。我喜欢uKolka的回答:

n.toLocaleString()

但不幸的是,在某些地区(例如西班牙语)中,它对于10,000以下的数字不起作用(IMHO):

Number(1000).toLocaleString('ES-es')

给与10001.000

请参阅toLocaleString在所有浏览器中小于10000的数字不起作用,以了解原因。

因此,我不得不使用Elias Zamaria的答案来选择正确的千位分隔符:

n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))

对于使用,.作为千位分隔符的两种语言环境,此代码都能很好地发挥作用,并且在所有情况下都从1,000开始。

Number(1000).toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))

给人1.000以西班牙语场所背景。

如果您想完全控制数字的格式,可以尝试以下方法:

let number   = 1234.567
let decimals = 2
let decpoint = '.' // Or Number(0.1).toLocaleString().substring(1, 2)
let thousand = ',' // Or Number(10000).toLocaleString().substring(2, 3)

let n = Math.abs(number).toFixed(decimals).split('.')
n[0] = n[0].split('').reverse().map((c, i, a) =>
  i > 0 && i < a.length && i % 3 == 0 ? c + thousand : c
).reverse().join('')
let final = (Math.sign(number) < 0 ? '-' : '') + n.join(decpoint)

console.log(final)

1,234.57

这个不需要正则表达式。首先,将数字调整为所需的小数位数toFixed,然后将其除以小数点(.如果有的话)。然后将左侧变成数字数组,将其反转。然后从头开始每三位数添加一个千位分隔符,结果再次取反。最终结果是两个部分的并集。Math.abs首先删除输入数字的符号,然后在必要时放回。

它不是单线的,但时间不长且容易转变为功能。为了清楚起见,添加了变量,但是如果事先知道,可以将其替换为所需的值。您可以使用表达式toLocaleString来查找小数点的正确字符和当前语言环境的千位分隔符(请记住,这些表达式需要更现代的Javascript。)


23

我认为这是最短的正则表达式:

/\B(?=(\d{3})+\b)/g

"123456".replace(/\B(?=(\d{3})+\b)/g, ",")

我检查了一些数字,它奏效了。


仅当浮点数在分隔符后没有超过3个数字的情况下才有效,在这种情况下为点。否则,它还会添加一个逗号。“ 1234567890.1234567890” .replace(/ \ B(?=(\ d {3})+ \ b)/ g,“,”)例如,这将不起作用。返回“ 1,234,567,890.1,234,567,890”
Marcio

1
虽然适用于货币!在添加逗号之前,只需四舍五入即可。
凯尔·查达

1
小数点后增加:12.3456“ .replace(/ \ B(?=(\ d {3})+ \ b)/ g,”,“)== 12.3,456
Shree Tiwari

21

Number.prototype.toLocaleString()如果它是所有浏览器(Safari)本地提供的,那将是很棒的。

我检查了所有其他答案,但似乎没有人将其填满。这是一个问题,实际上是前两个答案的结合。如果toLocaleString可行,则使用它,如果不可行,则使用自定义函数。

var putThousandsSeparators;

putThousandsSeparators = function(value, sep) {
  if (sep == null) {
    sep = ',';
  }
  // check if it needs formatting
  if (value.toString() === value.toLocaleString()) {
    // split decimals
    var parts = value.toString().split('.')
    // format whole numbers
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, sep);
    // put them back together
    value = parts[1] ? parts.join('.') : parts[0];
  } else {
    value = value.toLocaleString();
  }
  return value;
};

alert(putThousandsSeparators(1234567.890));


1
请注意,polyfill仅适用于最多具有3个小数的数字。例如:0.12345将输出0.12,345。这方面的一个很好的实现可以在找到underscore.string
安迪·

您说对了,将value > 1000if条件解决可以解决这种情况,但这是一个问题,当然可以在其他地方找到经过更好测试的版本,谢谢您指出。
锡南

1
放置不足value > 1000,因为对于任何数字和多于3个小数,它都是相同的。例如1000.12345返回1,000.12,345。您的答案很好,而且方向正确,但还没有完成。我只是想为其他可能会误解您答案的人指出,只需复制/粘贴即可,而无需使用不同的输入数据进行测试。
安迪

1
好吧,这需要另一次编辑:)我同意,但是现在至少在大多数情况下应该可以使用。
锡南

18

可以使用浏览器的Intl对象以国际友好的方式插入千位分隔符:

Intl.NumberFormat().format(1234);
// returns "1,234" if the user's locale is en_US, for example

有关更多信息,请参见MDN关于NumberFormat的文章,您可以指定区域设置行为或默认使用用户的行为。这一点更加简单,因为它尊重局部差异。许多国家/地区使用句点分隔数字,而逗号则表示小数。

Intl.NumberFormat并非在所有浏览器中都可用,但可以在最新的Chrome,Opera和IE中使用。Firefox的下一个版本应支持它。Webkit似乎没有实现时间表。


2
如果我们可以使用一个简单的内置函数,这将是很棒的,但是它具有糟糕的浏览器实现。例如,IE 8-10和所有Safari都不支持此功能
Blaine Kasten 2014年

@BlaineKasten这里有一个与旧版浏览器完全兼容的polyfill,可以在这里找到:github.com/andyearnshaw/Intl.js它很大,但是可以用。
曼恩2014年

1
可通过pollyfill CDN使用(仅返回基于useragent所需的内容):cdn.polyfill.io/v2/polyfill.min.js?features=Intl
Kevin

如果使用toLocaleString格式化大量数字时出现问题,则效果很好(使用
polyfill


14

如果您要处理货币值并进行大量格式化,那么可能值得添加微小的accounting.js来处理很多极端情况和本地化:

// Default usage:
accounting.formatMoney(12345678); // $12,345,678.00

// European formatting (custom symbol and separators), could also use options object as second param:
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99

// Negative values are formatted nicely, too:
accounting.formatMoney(-500000, "£ ", 0); // £ -500,000

// Simple `format` string allows control of symbol position [%v = value, %s = symbol]:
accounting.formatMoney(5318008, { symbol: "GBP",  format: "%v %s" }); // 5,318,008.00 GBP

1
链接不再起作用。但是看起来与此类似:openexchangerates.github.io/accounting.js
ush189

13

以下代码使用char扫描,因此没有正则表达式。

function commafy( num){
  var parts = (''+(num<0?-num:num)).split("."), s=parts[0], L, i=L= s.length, o='';
  while(i--){ o = (i===0?'':((L-i)%3?'':',')) 
                  +s.charAt(i) +o }
  return (num<0?'-':'') + o + (parts[1] ? '.' + parts[1] : ''); 
}

它显示出令人鼓舞的性能:http : //jsperf.com/number-formatting-with-commas/5

2015.4.26:修复了num <0时的问题。参见https://jsfiddle.net/runsun/p5tqqvs3/


这并不工作,commafy(-123456)它给-,123,456
wrossmck

这很棒!感谢您整理jsperf
fregante

此代码段是绝对的怪物,可以执行所有操作。
NiCk Newman

13

这是一个简单的函数,用于为千位分隔符插入逗号。它使用数组函数而不是RegEx。

/**
 * Format a number as a string with commas separating the thousands.
 * @param num - The number to be formatted (e.g. 10000)
 * @return A string representing the formatted number (e.g. "10,000")
 */
var formatNumber = function(num) {
    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('');
};

带有示例的CodeSandbox链接:https ://codesandbox.io/s/p38k63w0vq


1
嗨。这个例子很棒。但是也会在小数点后加上逗号。只是一个编辑: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,','); //因为我们刚向数组添加了另一个单位,所以递减4。索引-= 4; } return array.join()+ decimalPart; };
Aki143S 2012年

谢谢你,先生。这正是我所需要的。
阿米尔·侯赛因·艾哈迈迪

11

使用此代码可处理印度的货币格式。可以更改国家/地区代码以处理其他国家/地区的货币。

let amount =350256.95
var formatter = new Intl.NumberFormat('en-IN', {
  minimumFractionDigits: 2,
});

// Use it.

formatter.format(amount);

输出:

3,50,256.95

尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。阅读此
Shanteshwar Inde

@ShanteshwarInde我将添加其他上下文以改善答案的
确定性

11

您也可以使用Intl.NumberFormat构造函数。这是您的操作方法。

 resultNumber = new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(yourNumber); 

这不起作用的节点js。它没有以印度格式给出答复
Suraj Dalvi

7

在写这篇文章之前,我写了一篇。没有正则表达式,您实际上可以理解代码。

$(function(){
  
  function insertCommas(s) {

    // get stuff before the dot
    var d = s.indexOf('.');
    var s2 = d === -1 ? s : s.slice(0, d);

    // insert commas every 3 digits from the right
    for (var i = s2.length - 3; i > 0; i -= 3)
      s2 = s2.slice(0, i) + ',' + s2.slice(i);

    // append fractional part
    if (d !== -1)
      s2 += s.slice(d);

    return s2;

  }
  
  
  $('#theDudeAbides').text( insertCommas('1234567.89012' ) );
  
  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="theDudeAbides"></div>


1
我在函数的开头添加了s.toString(),因此它也可以接受数字,而不仅仅是字符串。这是我的首选答案,因为它可读性强,简洁明了,并且没有正则表达式答案似乎存在的错误。
FeFiFoFu

7
var formatNumber = function (number) {
  var splitNum;
  number = Math.abs(number);
  number = number.toFixed(2);
  splitNum = number.split('.');
  splitNum[0] = splitNum[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  return splitNum.join(".");
}

编辑:该功能仅适用于正数。例如:

var number = -123123231232;
formatNumber(number)

输出:“ 123,123,231,232”

但是回答以上toLocaleString()方法的问题只能解决问题。

var number = 123123231232;
    number.toLocaleString()

输出:“ 123,123,231,232”

欢呼!


1
尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
唐老鸭

1
不错的脚本,但不适用于负数。
拉尔夫·大卫·阿伯纳西

7

我的答案是用更明智的选择完全替代jQuery的唯一答案:

function $(dollarAmount)
{
    const locale = 'en-US';
    const options = { style: 'currency', currency: 'USD' };
    return Intl.NumberFormat(locale, options).format(dollarAmount);
}

此解决方案不仅添加逗号,而且在您输入的金额$(1000.9999)为$ 1,001.00 的情况下,也会四舍五入至最接近的美分。此外,您输入的值可以安全地是数字或字符串;例如,没关系

如果您正在处理货币,但是不想在金额上显示前导美元符号,则还可以添加此函数,该函数使用先前的函数,但删除了$

function no$(dollarAmount)
{
    return $(dollarAmount).replace('$','');
}

如果您花钱,并且对十进制格式要求有所不同,则可以使用以下更通用的功能:

function addCommas(number, minDecimalPlaces = 0, maxDecimalPlaces = Math.max(3,minDecimalPlaces))
{
    const options = {};
    options.maximumFractionDigits = maxDecimalPlaces;
    options.minimumFractionDigits = minDecimalPlaces;
    return Intl.NumberFormat('en-US',options).format(number);
}

哦,顺便说一句,此代码在某些旧版本的Internet Explorer中不起作用是完全有意的。我试图在不支持现代标准的情况下随时破坏IE。

请记住,在评论部分中,过度赞美被认为是题外话。相反,只要给我上投票即可。


1
Number(n).toLocaleString()似乎是最好的答案,但您可能想使用类似new Intl.NumberFormat('en-US')。format(n)之类的东西,而不是剥离所有美元符号和小数点(如果所有用户想要的数字是逗号。
bmacnaughton

@bmacnaughton:当您不处理金钱时,这是一个好点。但是,如果您正在处理货币,并且只是“不想使用美元开头的符号”,那么Number(1000.50).toLocaleString()会生成“ 1,000.5”,该数字将删除显示货币值时通常保留的微不足道的零。好的评论:每个人都应该知道你说的话。
朗尼·贝斯特

6

对我来说,最好的答案是像某些成员所说的那样使用toLocaleString。如果要包括'$'符号,只需添加languaje并键入options。这是将数字格式化为墨西哥比索的示例

var n = 1234567.22
alert(n.toLocaleString("es-MX",{style:"currency", currency:"MXN"}))

捷径

1234567.22.toLocaleString("es-MX",{style:"currency", currency:"MXN"})


5

另一种方法,支持小数,不同的分隔符和负数。

var number_format = function(number, decimal_pos, decimal_sep, thousand_sep) {
    var ts      = ( thousand_sep == null ? ',' : thousand_sep )
        , ds    = ( decimal_sep  == null ? '.' : decimal_sep )
        , dp    = ( decimal_pos  == null ? 2   : decimal_pos )

        , n     = Math.floor(Math.abs(number)).toString()

        , i     = n.length % 3 
        , f     = ((number < 0) ? '-' : '') + n.substr(0, i)
    ;

    for(;i<n.length;i+=3) {
        if(i!=0) f+=ts;
        f+=n.substr(i,3);
    }

    if(dp > 0) 
        f += ds + parseFloat(number).toFixed(dp).split('.')[1]

    return f;
}

@Jignesh Sanghani的一些更正,不要忘了赞扬他的评论。


非常适合我,只需添加新行以在处理之前删除格式即可。
丹尼斯·海登

2
fn.substr(0, i)替换为n.substr(0, i),也number.toFixed(dp).split('.')[1]替换为parseFloat(number).toFixed(dp).split('.')[1]。因为当我直接使用它会给我一个错误。请更新您的代码
Jignesh Sanghani

有缺陷的。数量增长。一次电话互助会很棒!
mmm

切换到固定的地板,但不确定还会发生什么其他问题。
mmm

1
试试Math.floor(-75.1);)
mmm,

4

我认为此功能将解决与此问题相关的所有问题。

function commaFormat(inputString) {
    inputString = inputString.toString();
    var decimalPart = "";
    if (inputString.indexOf('.') != -1) {
        //alert("decimal number");
        inputString = inputString.split(".");
        decimalPart = "." + inputString[1];
        inputString = inputString[0];
        //alert(inputString);
        //alert(decimalPart);

    }
    var outputString = "";
    var count = 0;
    for (var i = inputString.length - 1; i >= 0 && inputString.charAt(i) != '-'; i--) {
        //alert("inside for" + inputString.charAt(i) + "and count=" + count + " and outputString=" + outputString);
        if (count == 3) {
            outputString += ",";
            count = 0;
        }
        outputString += inputString.charAt(i);
        count++;
    }
    if (inputString.charAt(0) == '-') {
        outputString += "-";
    }
    //alert(outputString);
    //alert(outputString.split("").reverse().join(""));
    return outputString.split("").reverse().join("") + decimalPart;
}

4

仅针对未来的Google员工(或不一定是“ Google员工”):

上面提到的所有解决方案都很棒,但是,在这种情况下使用RegExp可能是一件很糟糕的事情。

所以,是的,您可以使用一些建议的选项,甚至编写一些原始但有用的东西,例如:

const strToNum = str => {

   //Find 1-3 digits followed by exactly 3 digits & a comma or end of string
   let regx = /(\d{1,3})(\d{3}(?:,|$))/;
   let currStr;

   do {
       currStr = (currStr || str.split(`.`)[0])
           .replace( regx, `$1,$2`)
   } while (currStr.match(regx)) //Stop when there's no match & null's returned

   return ( str.split(`.`)[1] ) ?
           currStr.concat(`.`, str.split(`.`)[1]) :
           currStr;

};

strToNum(`123`) // => 123
strToNum(`123456`) // => 123,456
strToNum(`-1234567.0987`) // => -1,234,567.0987

这里使用的regexp非常简单,循环将精确地完成工作所需的次数。

您可能会更好地对其进行优化,例如“ DRYify”代码等等。

然而,

(-1234567.0987).toLocaleString();

(在大多数情况下)将是更好的选择。

关键不是执行速度或跨浏览器兼容性。

在您希望向用户显示结果编号的情况下,.toLocaleString()方法使您能够与网站或应用程序的用户说相同的语言(无论他/他的语言是什么)。

根据ECMAScript文档的方法是在1999年引入的,我相信这样做的原因是希望Internet能够在某个时候将世界各地的人们连接起来,因此,需要一些“内部化”工具。

今天,互联网确实连接了我们所有人,因此,重要的是要记住,世界是一种我们可以想象的更复杂的方式,并且(几乎)我们所有人都在互联网中。

显然,考虑到人的多样性,因为我们会说不同的语言,重视不同的事物等,所以不可能为每个人保证完美的UX。正因为如此,尽可能地使事物本地化显得尤为重要。 。

因此,考虑到有一些特定的日期,时间,数字等表示标准,并且我们有一个工具可以以最终用户喜欢的格式显示这些内容,这并不是很罕见,而且几乎是不负责任的使用该工具(尤其是在我们希望向用户显示此数据的情况下)?

对我来说,在这种情况下使用RegExp而不是.toLocaleString()听起来有点像用JavaScript创建时钟应用并对其进行硬编码,从而仅显示布拉格时间(对于不住在布拉格的人),即使

new Date();

是根据最终用户的时钟返回数据。


为什么用const和=>编写函数?
OG肖恩

@OGSean我一直都会这样做,因为它是声明变量和函数的最方便的方法。另外,我认为这有助于使代码更简洁。
伊戈尔·科科夫

4

为那些喜欢单线的人提供的true正则表达式专用解决方案

你看到上面那些热情的球员吗?也许你可以打高尔夫球。这是我的中风。

n => `${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " ").replace(/(?<=\.(\d{3})+)\B/g, " ")

使用一个狭窄的空间(U + 2009)为千位分隔符,作为国际单位制表示,做第八版(2006年),其出版的“ SI手册:国际单位制(SI) ” (见第5.3节.4。)。第九版(2019年)建议为其使用空格(请参见第5.4.4节)。您可以使用任何所需的内容,包括逗号。


看到。

const integer_part_only = n => `${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " I ");
const fractional_part_only = n => `${n}`.replace(/(?<=\.(\d{3})+)\B/g, " F ");
const both = n => fractional_part_only(integer_part_only(n));

function demo(number) { // I’m using Chrome 74.
	console.log(`${number}
		 "${integer_part_only(number)}" (integer part only)
		 "${fractional_part_only(number)}" (fractional part only)
		 "${both(number)}" (both)
	`);
}
demo(Math.random() * 10e5);
demo(123456789.01234567);
demo(123456789);
demo(0.0123456789);


它是如何工作的?

对于整数部分

.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " I ")
  • .replace(……, " I ") 放入“我”
    • /……/g 在每个
      • \B 两个相邻数字的中间
        • (?=……)正面的LOOKAHEAD,右边的部分是
          • (\d{3})+ 一个或多个三位数的块
          • \b 后面跟一个非数字,例如句点,字符串的结尾等,
        • (?<!……)负向隐藏,不包括左边部分
          • \.\d+ 是一个点后跟数字(“有小数点分隔符”)。

对于小数部分

.replace(/(?<=\.(\d{3})+)\B/g, " F ")
  • .replace(……, " F ") 放“ F”
    • /……/g 在每个
      • \B 两个相邻数字的中间
        • (?<=……)正面表情,其左侧为
          • \. 小数点分隔符
          • (\d{3})+ 随后是一个或多个三位数的块。

角色类别界限

\d

匹配任何数字(阿拉伯数字)。等同于[0-9]

例如,

  • /\d//[0-9]/匹配2B2 is the suite number

\b

匹配单词边界。在此位置,一个单词字符不能跟随或紧随另一个单词字符,例如字母和空格之间。请注意,匹配的单词边界不包括在匹配中。换句话说,匹配的单词边界的长度为零。

例子:

  • /\bm/匹配min moon;
  • /oo\b/ooin 不匹配moon,因为oo后跟n一个单词字符;
  • /oon\b/匹配oonin moon,因为它oon是字符串的结尾,因此不跟单词字符;
  • /\w\b\w/ 绝不会匹配任何内容,因为一个单词字符之后都不能同时包含非单词和单词字符。

\B

匹配非单词边界。这是上一个和下一个字符属于同一类型的位置:要么都必须是单词,要么都必须是非单词。例如两个字母之间或两个空格之间。字符串的开头和结尾被视为非单词。与匹配的单词边界相同,匹配的非单词边界也不包括在匹配中。

例如,

  • /\Bon/匹配onat noon;
  • /ye\B/ye在中匹配possibly yesterday

浏览器兼容性


3

我在Aki143S的解决方案中添加了tofixed 。此解决方案使用点表示数千个分隔符,并使用逗号表示精度。

function formatNumber( num, fixed ) { 
    var decimalPart;

    var array = Math.floor(num).toString().split('');
    var index = -3; 
    while ( array.length + index > 0 ) { 
        array.splice( index, 0, '.' );              
        index -= 4;
    }

    if(fixed > 0){
        decimalPart = num.toFixed(fixed).split(".")[1];
        return array.join('') + "," + decimalPart; 
    }
    return array.join(''); 
};

例子;

formatNumber(17347, 0)  = 17.347
formatNumber(17347, 3)  = 17.347,000
formatNumber(1234563.4545, 3)  = 1.234.563,454

3

已经有很多好的答案。这是另一个,只是为了好玩:

function format(num, fix) {
    var p = num.toFixed(fix).split(".");
    return p[0].split("").reduceRight(function(acc, num, i, orig) {
        if ("-" === num && 0 === i) {
            return num + acc;
        }
        var pos = orig.length - i - 1
        return  num + (pos && !(pos % 3) ? "," : "") + acc;
    }, "") + (p[1] ? "." + p[1] : "");
}

一些例子:

format(77.03453, 2); // "77.03"
format(78436589374); // "78,436,589,374"
format(784, 4);      // "784.0000"
format(-123456);     // "-123,456"

这并不工作,format(-123456)它给-,123,456
wrossmck

1
固定的(尽管可能有一种更优雅的方式来执行此操作,而无需每次都检查标志)。无论如何,此更新使此功能可以使用负数。
韦恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.