一尘不染

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

javascript

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

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


阅读 155

收藏
2022-02-08

共2个答案

一尘不染

简化了它,因为我只是为我的特定目的寻找简单的东西。这是我所拥有的:

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

正则表达式使用 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防止正则表达式在字符串的开头放置逗号。

提到如果小数点后超过 3 位,此功能会在不需要的位置添加逗号。如果这是一个问题,您可以使用此功能:

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

@tjcrowder指出,现在 JavaScript 有lookbehind(支持信息),可以在正则表达式本身解决:

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

Hide code snippet

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*)是一个否定的lookbehind,表示匹配项前面不能有a,.后跟零个或多个数字。至少在 V8 中,否定的lookbehind 比splitandjoin解决方案。

2022-02-08
一尘不染

我很惊讶没有人提到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可能会很有趣。

2022-02-08