Jak vytisknout číslo s čárkami jako oddělovači tisíců v JavaScriptu

Snažím se vytisknout celé číslo v JavaScriptu s čárkami jako oddělovači tisíců. Například chci zobrazit číslo 1234567 jako „1 234 567“. Jak bych to udělal?

Zde je návod, jak to dělám:

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

Existuje jednodušší nebo elegantnější způsob, jak to udělat? Bylo by hezké, kdyby to fungovalo i s plováky, ale to není nutné. K rozhodování mezi tečkami a čárkami nemusí být specifické pro národní prostředí.

Odpověď

Použil jsem nápad z Kerryho odpovědi, ale zjednodušil jsem to, protože jsem jen hledal něco jednoduchého pro svůj konkrétní účel. Zde je to, co jsem udělal:

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

Regulární výraz používá 2 předběžná tvrzení:

  • kladné k vyhledání libovolného bodu v řetězci, který má za sebou násobek 3 číslic v řadě,
  • záporné tvrzení, aby se zajistilo, že bod má pouze přesně násobek 3 číslic. Náhradní výraz tam vloží čárku.

Pokud jej například předáte 123456789.01 , kladné tvrzení bude odpovídat každému místu nalevo od 7 (od 789 je násobek 3 číslic, 678 je násobek 3 číslic, 567 , atd.). Záporné tvrzení kontroluje, že násobek 3 číslic nemá za sebou žádné číslice. 789 má za sebou tečku, takže je to přesně násobek 3 číslic, takže tam jde čárka. 678 je násobkem 3 číslic, ale má 9 za ním, takže ty 3 číslice jsou součástí skupiny 4 a čárka tam nejde. Podobně pro 567 . 456789 je 6 číslic, což je násobek 3, takže před ním je čárka. 345678 je násobkem 3, ale má 9 za ním, takže tam žádná čárka nejde. A tak dále. B zabrání regulárnímu výrazu vložit čárku na začátek řetězce.

@neu-rah zmínil, že tato funkce přidává čárky na nežádoucí místa, pokud jsou za desetinnou čárkou více než 3 číslice. Pokud se jedná o problém, můžete použít tuto funkci:

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

@t.j.crowder poukázal na to, že nyní, když má JavaScript lookbehind (informace o podpoře), lze to vyřešit v samotném regulárním výrazu:

function numberWithCommas(x) {
    return x.toString().replace(/B(?<!.d*)(?=(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(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*) je negativní lookbehind, který říká, že shodě nemůže předcházet . následuje nula nebo více číslic. Negativní lookbehind je rychlejší než split a join řešení (srovnání), alespoň ve V8.