如何在 JavaScript 中使用逗号作为千位分隔符打印数字

IT技术 javascript formatting numbers integer
2020-12-23 00:17:11

我试图用逗号作为千位分隔符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;
}

有没有更简单或更优雅的方法来做到这一点?如果它也适用于浮点数会很好,但这不是必需的。在句点和逗号之间做出决定不需要特定于语言环境。

6个回答

我使用了 Kerry's answer 中的想法,但简化了它,因为我只是为了我的特定目的寻找简单的东西。这是我所做的:

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 组的一部分,逗号不会出现在那里。对于567. 456789是 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*)是一个否定的lookbehind,表示匹配不能在前面加上.零个或多个数字。负向后视比splitjoin解决方案(比较更快,至少在 V8 中是这样。

试试 numberWithCommas(12345.6789) -> "12,345.6,789" 我不喜欢
2021-02-13 00:17:11
这在 safari 中不起作用。破坏了我的整个应用程序并让我永远弄清楚这是问题所在
2021-02-20 00:17:11
非常酷,但确实注意到小数点后超过 3 位的数字存在问题。
2021-02-27 00:17:11
@DmitrijGolubev 不适用于整数。也许强制小数点将是解决方案。
2021-03-01 00:17:11
'.' 后修复的小改进 问题 '123456789.01234'.replace(/\B(?=(?=\d*\.)(\d{3})+(?!\d))/g, '_')
2021-03-07 00:17:11

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

var n = 34523453.345;
console.log(n.toLocaleString());    // "34,523,453.345"

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

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

@MSC你应该尝试parseInt("1234567", 10).toLocaleString('en-US', {minimumFractionDigits: 2})new Number("1234567").toLocaleString('en-US', {minimumFractionDigits: 2})代替。它不起作用,因为您在字符串而不是数字上使用它。
2021-02-07 00:17:11
性能差异可能是也可能不是问题,具体取决于上下文。如果用于包含 1000 个结果的巨型表,则它会更重要,但如果仅用于单个值,则差异可以忽略不计。但优点是它可以识别区域设置,因此欧洲人会看到34.523.453,34534 523 453,345这对于有来自许多国家/地区的访问者的网站来说更为重要。
2021-02-20 00:17:11
惊人的。最后一个带有本机功能的答案。更重要的是,这个在不同国家正确显示,使用不同的分隔符(在捷克共和国我们写X XXX XXX,YYY)。
2021-02-22 00:17:11
googlers 更新:toLocaleString从 v0.12 开始,通过包含 Intl在 Node.js 中工作
2021-02-27 00:17:11
@csigrist 好点,但并不像看起来那么糟糕。速度取决于浏览器。在 FF 或 Opera 中它表现良好。不过我很讨厌 Chrome。至于零:var number = 123456.000; number.toLocaleString('en-US', {minimumFractionDigits: 2}); "123,456.00"尽管这些选项在 FF 或 Safari 中不起作用。
2021-02-28 00:17:11

下面是两个不同的浏览器 API,可以将Numbers转换为结构化的Strings请记住,并非所有用户的机器都有在 numbers 中使用逗号区域设置要对输出强制使用逗号,可以使用任何“西方”语言环境,例如en-US

let number = 1234567890; // Example number to be converted

⚠️ 请注意 javascript 的最大整数值为9007199254740991


// 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"

数字格式

let number = 1234567890;
let nf = new Intl.NumberFormat('en-US');
nf.format(number); // "1,234,567,890"

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

现场演示https : //codepen.io/vsync/pen/MWjdbgL?editors = 1000

正如其他人所指出的,number.toLocaleString不适用于所有浏览器,也不适用于 PhantomJS。Number.toLocaleString() 没有应用适当的格式
2021-02-11 00:17:11
minimumFractionDigits: 2也可以添加以确保固定的小数位数stackoverflow.com/questions/31581011/...
2021-02-25 00:17:11
toLocaleString解决方案应该可能还包括所需的语言环境,所以toLocaleString("en"),因为英国模式使用逗号。但是,如果toLocaleString()在法国运行没有区域设置指示符,那么它将产生句点而不是逗号,因为这是用于在本地分隔数千个的。
2021-03-01 00:17:11
toLocaleStringSafari 上的基本工作,选项没有
2021-03-03 00:17:11
浏览器支持总是在我链接到的每个 MDN 页面的底部提到。
2021-03-05 00:17:11

我建议使用 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;
}

@ernix - 它与 OP 给出的示例完全一样。我放了一个小提琴,所以你可以看到。
2021-02-10 00:17:11
@ernix - 操作员要求使用 JavaScript,我给出的答案JavaScript。这是 PHP 函数的 JavaScript 解释。
2021-02-12 00:17:11
@Andrew S - 只有 1 人将其标记下来。它确实有效,我在自己的代码中多次使用它。这也不是我的代码(也不是我的测试),我引用了它来自的站点,这是一个众所周知的站点。也许他们有它的更新版本),因为您正在查看的代码已有 3 年历史。
2021-02-15 00:17:11
@ernix - 好的,但关键是它完全符合 OP 的要求。它来自另一个站点(不是由我维护的,我之前已经说明过),并且在为其提供适当的变量时,它的工作原理与所述完全相同。如果您认为这是一个错误,请联系 phpjs.org 或查看他们是否有更新版本。
2021-02-24 00:17:11
太棒了。我一直在寻找,只找到了令人难以置信的臃肿库,甚至不允许我更改千位和小数点分隔符。
2021-02-25 00:17:11

这是@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] : "");
}
2021-02-17 00:17:11