javascript - Hvordan formatere et tall med komma som tusenskilletegn?
Jeg prøver å skrive ut et heltall i JavaScript med komma som tusenskilletegn. For eksempel vil jeg vise tallet 1234567 som "1,234,567". Hvordan kan jeg gå frem for å gjøre dette?
Slik gjør jeg det:
function numberWithCommas(x) {
x = x.toString();
var pattern = /(-?\d+)(\d{3})/;
while (pattern.test(x))
x = x.replace(pattern, "$1,$2");
return x;
}
console.log(numberWithCommas(1000))Finnes det en enklere eller mer elegant måte å gjøre det på? Det hadde vært fint om det også fungerer med desimaltall, men det er ikke nødvendig. Det trenger ikke å være lokaliseringsspesifikt for å avgjøre mellom punktum og komma.
Svar #1
Jeg brukte ideen fra Kerrys svar, men forenklet den siden jeg bare var ute etter noe enkelt for mitt spesifikke formål. Her er hva jeg har:
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;
}Regexen bruker 2 fremoverblikk-påstander:
- en positiv en å se etter ethvert punkt i strengen som har et multiplum av 3 sifre på rad etter seg,
- en negativ påstand for å sikre at punktet kun har nøyaktig et multiplum av 3 sifre. Erstatningsuttrykket setter et komma der.
For eksempel, hvis du gir det 123456789.01, vil den positive påstanden matche hvert sted til venstre for 7 (siden 789 er et multiplum av 3 sifre, 678 er et multiplum av 3 sifre, 567, osv.). Den negative påstanden sjekker at multiplumet av 3 sifre ikke har noen sifre etter seg. 789 har et punktum etter seg, så det er akkurat et multiplum av 3 sifre, dermed kommer det et komma der. 678 er et multiplum av 3 sifre, men det har en 9 etter seg, så disse 3 sifrene er en del av en gruppe på 4, og et komma settes ikke der. På samme måte for 567. 456789 er 6 sifre, som er et multiplum av 3, så et komma settes foran det. 345678 er et multiplum av 3, men det har en 9 etter seg, så det settes ikke noe komma der. Og så videre. \B hindrer regex fra å sette et komma i begynnelsen av strengen.
@neu-rah nevnte at denne funksjonen legger til komma på uønskede steder hvis det er mer enn 3 sifre etter desimalpunktet. Hvis dette er et problem, kan du bruke denne funksjonen:
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 påpekte at nå som JavaScript har lookbehind (støtteinformasjon), kan det løses i selve regulære uttrykket:
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*) er en negativ lookbehind som sier at treffet ikke kan etterfølges av en . fulgt av null eller flere sifre. Den negative lookbehinden er raskere enn split og join-løsningen (sammenligning), i det minste i V8.
Svar #2
Jeg er overrasket over at ingen nevnte Number.prototype.toLocaleString. Det er implementert i JavaScript 1.5 (som ble introdusert i 1999), så det er i utgangspunktet støttet i alle store nettlesere.
var n = 34523453.345;
console.log(n.toLocaleString()); // "34,523,453.345"Det fungerer også i Node.js fra og med v0.12 via inkludering av Intl
Hvis du vil ha noe annerledes, kan Numeral.js være interessant.
Svar #3
Nedenfor er to forskjellige nettleser-APIer som kan transformere Numre til strukturerte Strenger. Husk at ikke alle brukeres maskiner har en lokalitet som bruker komma i tall. For å tvinge komma i output, kan hvilken som helst "vestlig" lokalitet brukes, for eksempel en-US
let number = 1234567890; // Example number to be converted
⚠️ Husk at javascript har en maksimal heltallsverdi på 9007199254740991
tilLokaltStreng
// default behaviour on a machine with a locale 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"
//You can also force a minimum of 2 trailing digits
let number3 = 1.5;
number3.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2}); //"1.50"
NumberFormat
let number = 1234567890;
let nf = new Intl.NumberFormat('en-US');
nf.format(number); // "1,234,567,890"
Fra det jeg har sjekket (i det minste med Firefox) er de begge mer eller mindre like når det gjelder ytelse.
⚡ Direkte demo: https://codepen.io/vsync/pen/MWjdbgL?editors=1000
Svar #4
Jeg foreslår å bruke phpjs.org sin number_format()
function number_format(number, decimals, dec_point, thousands_sep) {
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);
}
OPPDATERING 13.02.14
Folk har rapportert at dette ikke fungerer som forventet, så jeg laget en JS Fiddle som inkluderer automatiserte tester.
Oppdatering 26.11.2017
Her er den fiolinen som et Stack-eksempel med litt endret utdata:
function number_format(number, decimals, dec_point, thousands_sep) {
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;
}Svar #5
Dette er en variant av @mikez302 sitt svar, men modifisert for å støtte tall med desimaler (i henhold til @neu-rah sin tilbakemelding om at numberWithCommas(12345.6789) -> "12,345.6,789" i stedet for "12,345.6789"
function numberWithCommas(n) {
var parts=n.toString().split(".");
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}
Svar #6
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
Svar #7
Bruke regulært uttrykk
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
Bruke 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
ref MDN:Number.prototype.toLocaleString()
Bruke 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
DEMO HER
<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>Ytelse
Svar #8
Intl.NumberFormat
Native JS-funksjon. Støttes av IE11, Edge, nyeste Safari, Chrome, Firefox, Opera, Safari på iOS og Chrome på Android.
var number = 3500;
console.log(new Intl.NumberFormat().format(number));
// → '3,500' if in US English locale
Svar #9
Jeg er ganske imponert over antallet svar dette spørsmålet har fått. Jeg liker svaret fra uKolka:
n.toLocaleString()
Men dessverre, i noen lokaler som spansk, fungerer det (etter min mening) ikke som forventet for tall under 10 000:
Number(1000).toLocaleString('ES-es')
Gir 1000 og ikke 1.000.
Se at toLocaleString ikke fungerer på tall mindre enn 10000 i alle nettlesere for å vite hvorfor.
Så jeg måtte bruke svaret fra Elias Zamaria og velge riktig tusenskillertegn:
n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))
Denne fungerer godt som en enkel linje for begge lokaliteter som bruker , eller . som tusenskiller og begynner å virke fra 1 000 i alle tilfeller.
Number(1000).toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))
Gir 1.000 med spansk lokal kontekst.
Hvis du ønsker å ha absolutt kontroll over hvordan et tall blir formatert, kan du også prøve følgende:
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)
Gir 1,234.57.
Denne trenger ikke et regulært uttrykk. Den fungerer ved først å justere tallet til ønsket antall desimaler med toFixed, og deretter dele det rundt desimalpunktet . hvis det finnes et. Venstre side blir så gjort om til et array av sifre som blir reversert. Deretter legges et tusenskille til for hver tredje siffer fra starten, og resultatet reverseres igjen. Det endelige resultatet er sammenslåingen av de to delene. Tegnet på inntastet tall fjernes først med Math.abs og settes deretter tilbake om nødvendig.
Det er ikke en énlinjer, men ikke mye lengre og enkelt å gjøre om til en funksjon. Variabler har blitt lagt til for klarhet, men disse kan erstattes med de ønskede verdiene hvis de er kjent på forhånd. Du kan bruke uttrykkene som bruker toLocaleString som en måte å finne ut de riktige tegnene for desimalpunkt og tusenskiller for gjeldende lokalitet (vær oppmerksom på at disse krever en mer moderne Javascript).
Svar #10
Takk til alle for svarene deres. Jeg har bygget videre på noen av svarene for å lage en mer "én-størrelse-passer-alle"-løsning.
Den første kodesnutten legger til en funksjon som etterligner PHPs number_format() til Number-prototypen. Hvis jeg formaterer et tall, ønsker jeg vanligvis desimaler, så funksjonen tar inn antall desimaler som skal vises. Noen land bruker komma som desimaltegn og punktum som tusenskilletegn, så funksjonen lar disse skilletegnene settes.
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);
}
Du ville bruke dette på følgende måte:
var foo = 5000;
console.log(foo.numberFormat(2)); // us format: 5,000.00
console.log(foo.numberFormat(2, ',', '.')); // european format: 5.000,00
Jeg oppdaget at jeg ofte trengte å få tallet tilbake for matematiske operasjoner, men parseFloat konverterer 5,000 til 5, og tar ganske enkelt den første sekvensen av heltallsverdier. Så jeg laget min egen flyttalls-konverteringsfunksjon og la den til i String-prototypen.
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));
}
Nå kan du bruke begge funksjonene som følger:
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
Svar #11
Jeg tror dette er det korteste regulære uttrykket som gjør det:
/\B(?=(\d{3})+\b)/g
"123456".replace(/\B(?=(\d{3})+\b)/g, ",")
Jeg sjekket det på noen få tall, og det fungerte.
Svar #12
Du kan enten bruke denne prosedyren for å formatere valutaen din som trengs.
var nf = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
nf.format(123456.789); // ‘$123,456.79’
For mer informasjon kan du få tilgang til denne lenken.
https://www.justinmccandless.com/post/formatting-currency-in-javascript/
Svar #13
Tusenvisseparatoren kan settes inn på en internasjonalvennlig måte ved å bruke nettleserens Intl-objekt:
Intl.NumberFormat().format(1234);
// returns "1,234" if the user's locale is en_US, for example
Se MDNs artikkel om NumberFormat for mer informasjon, du kan spesifisere lokasjonsadferd eller bruke brukerens standard. Dette er litt mer idiotsikkert fordi det respekterer lokale forskjeller; mange land bruker punktum for å separere sifre mens et komma angir desimaler.
Intl.NumberFormat er ennå ikke tilgjengelig i alle nettlesere, men det fungerer i siste versjon av Chrome, Opera og IE. Firefoxs neste utgivelse bør støtte det. Webkit ser ikke ut til å ha en tidslinje for implementering.
Svar #14
Number.prototype.toLocaleString() ville ha vært flott hvis det ble levert innfødt av alle nettlesere (Safari).
Jeg sjekket alle de andre svarene, men ingen så ut til å polyfille det. Her er et bevis på konsept for det, som faktisk er en kombinasjon av de to første svarene; hvis toLocaleString fungerer, bruker det det, hvis ikke, bruker det en egendefinert funksjon.
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));Svar #15
Hvis du jobber mye med valutaverdier og formatering, kan det være verdt å legge til tiny accounting.js som håndterer mange kanttilfeller og lokalisering:
// 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
Svar #16
Følgende kode bruker char scan, så det er ingen regex.
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] : '');
}
Den viser lovende ytelse: http://jsperf.com/number-formatting-with-commas/5
2015.4.26: Mindre fiks for å løse problem når num<0. Se https://jsfiddle.net/runsun/p5tqqvs3/
Svar #17
Her er en enkel funksjon som setter inn komma som tusenskilletegn. Den bruker array-funksjoner i stedet for en 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-lenk med eksempler: https://codesandbox.io/s/p38k63w0vq
Svar #18
Bruk denne koden for å håndtere valutaformat for India. Landkode kan endres for å håndtere valuta for andre land.
let amount =350256.95
var formatter = new Intl.NumberFormat('en-IN', {
minimumFractionDigits: 2,
});
// Use it.
formatter.format(amount);
utdata :
3,50,256.95
Svar #19
Universell, rask, nøyaktig, enkel funksjon
- Bruke RegEx (Raskt og nøyaktig)
- Støtt tall (flyttall/heltall)/streng/flere tall i en streng
- Smart brønn (Ikke grupper desimaler - Kompatibel med forskjellige typer gruppering)
- Støtter alle nettlesere, spesielt 'Safari' og 'IE' og mange eldre nettlesere
- [Valgfritt] Respektere ikke-engelske (persiske/arabiske) sifre (+ prefiks)
TL;DR - Fullversjon funksjon (minifisert):
// num: Number/s (String/Number),
// sep: Thousands separator (String) - Default: ','
// dec: Decimal separator (String) - Default: '.' (Just one char)
// u: Universal support for languages characters (String - RegEx character set / class) - Example: '[\\d\\u0660-\\u0669\\u06f0-\\u06f9]' (English/Persian/Arabic), Default: '\\d' (English)
function formatNums(num,sep,dec,u){sep=sep||',';u=u||'\\d';if(typeof num!='string'){num=String(num);if(dec&&dec!='.')num=num.replace('.',dec);}return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a){return a.length==1?a+sep:a})}
text='100000000 English or Persian/Arabic ۱۲۳۴۵۶۷۸۹/٠١٢٣٤٥٦٧٨٩ this is 123123123.123123123 with this -123123 and these 10 100 1000 123123/123123 (2000000) .33333 100.00 or any like 500000Kg';
console.log(formatNums(10000000.0012));
console.log(formatNums(10000000.0012,'.',',')); // German
console.log(formatNums(text,',','.','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]')); // Respect Persian/Arabic digits<input oninput="document.getElementById('result').textContent=formatNums(this.value)" placeholder="Type a number here">
<div id="result"></div>Hvorfor er du IKKE fornøyd med andre svar?
Number.prototype.toLocaleString()/Intl.NumberFormat (Riktig svar)
- Hvis det ikke finnes gode argumenter, kan vi ikke forvente samme resultat. Selv med argumentalternativer kan vi fortsatt ikke være sikre på hva resultatet kan bli, fordi det vil bruke lokale innstillinger og mulige klientmodifikasjoner påvirker det, eller at nettleseren/enheten ikke støtter det.
- >~2016 nettlesere støttes og fortsatt i 2021 finnes det noen rapporter om at i noen tilfeller som i
SafariellerIE/Edgereturneres ikke som forventet. toLocaleString()fungerer med tall,Intl.NumberFormatfungerer med strenger/tall; strenger må være/parses og avrundes også om nødvendig, så:- Hvis vi allerede har en lokalisert streng med
ikke-engelske sifre, må vi erstatte tallene med de engelske, deretter analysere det, og deretter bruke det igjen med de lokale alternativene. (Hvis det returnerer det vi forventer)
- Hvis vi allerede har en lokalisert streng med
- Generelt sett kan vi under parsing ikke forvente å ikke
mangle desimalnullereller detaljer istore talleller å respekteretalltegn fra andre språk
∕ brøk-/divisjonstegn som desimalskilletegn)Ikke så gode RegEx-metoder (Raskeste og énlijnsmetoder)
/\B(?=(\d{3})+\b)/det vil også gruppere desimaler.// 123,123.123,123 !!!
/(?<!\.\d+)\B(?=(\d{3})+\b)/ brukte look-behind som enda ikke støttes godt. Vennligst sjekk:https://caniuse.com/js-regexp-lookbehind
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility
Merk: Generelt kan lookbehind være i konflikt med den opprinnelige RegEx-strukturen (på grunn av hvordan analyset bør fungere, som å ikke bufre det rå bak som en parser) og det kan faktisk gjøre ytelsen betydelig lavere (i dette tilfellet ~30%). Jeg tror det har blitt presset inn over tid etter forespørsler.
/\B(?=(?=\d*\.)(&\d{3})+(?!\d))/ fungerer bare med desimaltall og ignorerer heltall..replace(/(?:[^.\d]|^)\d+/g,function(a){return a.replace(/\B(?=(?:\d{3})+\b)/g,',');}) (Min gamle idé) Bruke 2 RegEx. Den første finner heltallene, den andre setter inn skilletegn. Hvorfor 2 funksjoner, når det kan blandes?/(\..*)$|(\d)(?=(\d{3})+(?!\d))/g (God idé av @djulien - jeg stemte ja) men når RegEx er global, (\..*)$ kan det gjøre en feil selv med et mellomrom til slutt.
Å bruke fangstgrupper (Eksempel: (\d)) vil også gjøre ytelsen lav, så hvis mulig, bruk ikke-fangst grupper (Eksempel: (?:\d)) eller hvis en setning allerede finnes i funksjonen vår, la oss blande den.
I dette tilfellet forbedrer det ytelsen med å ikke bruke fangstgrupper med omtrent ~20% og i tilfelle /\B(?=(\d{3})+\b)/g vs /\B(?=(?:\d{3})+\b)/g, er den andre ~8% raskere.
Om regex-ytelser:
Merk: Ulike metoder, nettlesere, maskinvare, systemstatus, tilfeller og til og med endringer i ECMAScript vil påvirke resultatet av ytelsestesting. Men noen endringer burde logisk påvirke resultatet, og jeg brukte dette bare som et visuelt eksempel.
.split('.') eller .toFixed() eller Math.floor() ...Endelig resultat:
Det finnes ingen som er best av alle, og det bør velges basert på behovet. Min prioritet for sortering;
- Kompatibilitet
- Evne
- Universellhet
- Brukervennlighet
- Ytelse
toLocaleString() (Kompatibilitet - Universalitet) [Innebygd funksjon]
- Hvis du må endre sifre og gruppering fra engelsk til et annet språk
- Hvis du ikke er sikker på språket til klienten din
- Hvis du ikke trenger å ha nøyaktig forventet resultat
- Hvis du ikke bryr deg om eldre versjon av Safari
// 1000000.2301
parseFloat(num) // (Pre-fix) If the input is string
.toLocaleString('en-US', {
useGrouping: true // (Default is true, here is just for show)
});
// 1,000,000.23
Les mer: https://www.w3schools.com/jsref/jsref_tolocalestring_number.asp
Intl.NumberFormat() (Mulighet - Universalitet - Kompatibilitet) [Innebygd funksjon]
Nesten det samme som toLocaleString() +
- Stor evne til å støtte valuta, enheter, osv... hvilket som helst språk (Moderne nettlesere)
// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣
Les mer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
Med disse mange alternativene til de innebygde funksjonene, kan vi fortsatt ikke forvente:
- Eksakt resultat (+ Ikke analysere input/Ikke runde/Ikke konvertere store tall)
- Aksepterer sifre fra andre språk som inndata
- Tilpasse skilletegn
- Støtte for pålitelige nettlesere
- Ytelse
Så du trenger kanskje en funksjon som noen av disse:
formatNums() (Kompatibilitet - Brukervennlighet)
Full versjon (Kapabilitet) (Ikke raskere enn toLocaleString) - Forklar:
function formatNums(num, sep, dec, u) {
// Setting defaults
sep = sep || ','; // Seperator
u = u || '\\d'; // Universal character set \d: 0-9 (English)
// Mixing of Handeling numbers when the decimal character should be changed + Being sure the input is string
if (typeof num != 'string') {
num = String(num);
if (dec && dec != '.') num = num.replace('.', dec); // Replacing sure decimal character with the custom
}
//
return num.replace(RegExp('\\' + (dec || '.') + u + '+|' + u + '(?=(?:' + u + '{3})+(?!' + u + '))', 'g'),
// The RegEx will be like /\.\d+|\d(?=(?:\d{3})+(?!\d))/g if not be customized
// RegEx explain:
// 1) \.\d+ : First try to get any part that started with a dot and followed by any much of English digits, one or more (For ignoring it later)
// 2) | : Or
// 3) \d : Get any 1 char digit
// 3.1) (?=...) : That the next of that should be
// 3.2) (?:\d{3}) : 3 length digits
// 3.2.1) + : One or more of the group
// 3.3) (?!\d) : ...till any place that there is no digits
function(a) { // Any match can be the decimal part or the integer part so lets check it
return a.length == 1 ? a + sep : a // If the match is one character, it is from the grouping part as item (3) in Regex explain so add the seperator next of it, if not, ignore it and return it back.
})
}
function formatNums(num,sep,dec,u) {
sep=sep||',';
u=u||'\\d';
if(typeof num!='string') {
num=String(num);
if( dec && dec!='.') num=num.replace('.',dec);
}
return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+'{3})+(?!'+u+'))','g'),function(a) {return a.length==1 ? a+sep : a})
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' , '));
console.log(formatNums('0000.0000'));
console.log(formatNums('5000000.00'));
console.log(formatNums('5000000,00',' ',','));
console.log(formatNums(5000000.1234,' ',','));
console.log(formatNums('۱۲۳۴۵۶۷۸۹/۹۰۰۰',',','/','[\\d\\u0660-\\u0669\\u06f0-\\u06f9]'));Lek med eksemplene her: https://jsfiddle.net/PAPIONbit/198xL3te/
Lett versjon (Ytelse) (~30 % raskere enn toLocaleString)
function formatNums(num,sep) {
sep=sep||',';
return String(num).replace(/\.\d+|\d(?=(?:\d{3})+(?!\d))/g,
function(a) {
return a.length==1?a+sep:a
}
);
}
console.log(formatNums(1000000.2301));
console.log(formatNums(100.2301));
console.log(formatNums(-2000.2301));
console.log(formatNums(123123123,' '));Sjekk RegEx (uten den nødvendige funksjonen) : https://regexr.com/66ott
(num+'').replace(/\B(?=(?:\d{3})+\b)/g,','); (Ytelse - Kompatibilitet)
Beste valg hvis inndataene er spesifisert/forhåndsdefinert. (Som vanlige priser som helt sikkert ikke vil ha mer enn 3 desimaler) (~65 % raskere enn toLocaleString)
num=1000000;
str='123123.100';
console.log((num+'').replace(/\B(?=(?:\d{3})+\b)/g,','));
console.log(str.replace(/\B(?=(?:\d{3})+\b)/g,','));+
For persiske/arabiske lokale kunder:
Hvis klienten din skal bruke persiske/arabiske tall for input slik det er vanlig i Iran, tror jeg den beste måten er i stedet for å beholde de originale tegnene, å konvertere dem til engelsk før du håndterer dem, slik at du kan beregne det.
// ۱۲۳۴۵۶۷۸۹۰
function toEnNum(n) { // Replacing Persian/Arabic numbers character with English
n.replace(/[\u0660-\u0669\u06f0-\u06f9]/g, // RegEx unicode range Persian/Arabic numbers char
function(c) {
return c.charCodeAt(0) & 0xf; // Replace the char with real number by getting the binary index and breaking to lowest using 15
}
);
}
// 1234567890
Og for fortsatt å vise dem som opprinnelige ser det er 2 måter:
- CSS Bruke persiske/arabiske skrifttyper med lokale sifre (Mitt valg)
- Konverter resultatet tilbake med
Intl.NumberFormateller en funksjon som: https://stackoverflow.com/a/13787021/7514010
Min gammeldagse funksjon på dette innlegget: (~15 % raskere enn toLocalString)
// 10000000.0012
function formatNums(n, s) {
return s = s || ",", String(n).
replace(/(?:^|[^.\d])\d+/g, // First this RegEx take just integer parts
function(n) {
return n.replace(/\B(?=(?:\d{3})+\b)/g, s);
})
}
// 10,000,000.0012
Svar #20
Du kan også bruke Intl.NumberFormat-konstruktøren. Slik kan du gjøre det.
resultNumber = new Intl.NumberFormat('en-IN', { maximumSignificantDigits: 3 }).format(yourNumber);
Svar #21
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(".");
}
REDIGER: Funksjonen fungerer bare med positive tall. for eksempel:
var number = -123123231232;
formatNumber(number)
Output: "123,123,231,232"
Men for å svare på spørsmålet ovenfor løser toLocaleString()-metoden bare problemet.
var number = 123123231232;
number.toLocaleString()
Output: "123,123,231,232"
Skål!

