我试图在JavaScript中打印一个整数,用逗号作为千位分隔符。例如,我想将数字1234567显示为“1234567”。我该怎么做?

我是这样做的:

函数编号WithCommas(x){x=x.toString();var模式=/(-?\d+)(\d{3})/;while(模式测试(x))x=x.replace(模式,“$1,$2”);返回x;}console.log(数字与逗号(1000))

有没有更简单或更优雅的方法?如果它也可以与浮点运算一起使用,那就很好了,但这不是必须的。它不需要特定于区域设置来决定句点和逗号。


当前回答

我找到了一种适用于所有情况的方法。CodeSandbox示例

function commas(n) {
  if (n < 1000) {
    return n + ''
  } else {
    // Convert to string.
    n += ''

    // Skip scientific notation.
    if (n.indexOf('e') !== -1) {
      return n
    }

    // Support fractions.
    let i = n.indexOf('.')
    let f = i == -1 ? '' : n.slice(i)
    if (f) n = n.slice(0, i)

    // Add commas.
    i = n.length
    n = n.split('')
    while (i > 3) n.splice((i -= 3), 0, ',')
    return n.join('') + f
  }
}

这就像诺亚·弗雷塔斯(Noah Freitas)的答案,但支持分数和科学记数法。

我认为如果性能不受关注,toLocaleString是最好的选择。

edit:这里有一个CodeSandbox,其中包含一些示例:https://codesandbox.io/s/zmvxjpj6x

其他回答

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

2014年2月13日更新

人们一直在报告这并不像预期的那样奏效,所以我做了一个包含自动化测试的JSFiddle。

更新日期:2017年11月26日

这是一个稍微修改了输出的堆栈片段:

函数number_format(数字,小数,小数点,千位整){变量n=!是有限的(+数字)?0:+数字,prec=!是有限的(+小数)?0:数学abs(小数),sep=(typeof thousands_sep===“undefined”)?“,”:千分之一秒,dec=(dec_point类型==“未定义”)?“.”:dec_点,toFixedFix=函数(n,prec){//修复IE parseFloat(0.55).toFixed(0)=0;var k=数学功率(10,prec);return数学舍入(n*k)/k;},s=(prec?toFixedFix(n,prec):数学舍入(n)).toString().split('.');如果(s[0]。长度>3){s[0]=s[0]。替换(/\B(?=(?:\d{3})+(?!\d))/g,sep);}if((s[1]||'').length<prec){s[1]=s[1]| |“”;s[1]+=新数组(prec-s[1].length+1).join('0');}return s.join(十二月);}var exampleNumber=1;函数测试(预期,数字,小数,小数点,千分位){var actual=number_format(数字,小数,小数点,千位整);控制台日志('测试用例'+exampleNumber+':'+'(小数:'+(小数类型=='未定义'?'(默认)':小数)+',dec_point:“'+(dec_point类型=='未定义'?'(默认)':dec_point)+'”'+',thousands_sep:“'+(类型的thousands-sep==='未定义'?'(默认值)':thousand_sep)+'”)');console.log('=>'+(实际==预期?'通过':'失败')+',得到“'+实际+'”,预期“'+预期+'”。');示例编号++;}测试('1235',1234.56);测试('1234,56',1234.56,2,',','');测试('1234.57',1234.5678,2,'.','');测试('67,00',67,2,',','.');测试(“1000”,1000);测试(‘67.31’,67.311,2);试验(‘1000.6’,1000.55,1);测试('67.00000000',67000,5,',','.');测试('1',0.9,0);试验(‘1.20’,‘1.20‘,2);测试(‘12000’,‘1.20’,4);测试('1.200','1.2000',3);.作为控制台包装{最大高度:100%!重要的}

仅适用于未来的谷歌人(或不一定是“谷歌人”):

上面提到的所有解决方案都很好,然而,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

这里使用的正则表达式相当简单,循环将精确到完成任务所需的次数。

你可能会优化得更好,“DRYify”代码等等。

然而

(-1234567.0987).toLocaleString();

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

重点不在于执行速度或跨浏览器兼容性。

在您想向用户显示结果数字的情况下,.toLocaleString()方法可以让您与网站或应用程序的用户使用相同的语言(无论她/他的语言是什么)。

根据ECMAScript文档,这种方法于1999年引入,我认为其原因是希望互联网在某个时刻将连接世界各地的人们,因此需要一些“内部化”工具。

今天,互联网确实连接了我们所有人,因此,重要的是要记住,世界比我们想象的更复杂&我们(几乎)都在互联网中。

显然,考虑到人的多样性,不可能保证每个人都有完美的用户体验,因为我们讲不同的语言,看重不同的东西,等等。正因为如此,尽可能地将事情本地化更为重要。

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

对我来说,在这种情况下使用RegExp而不是.toLocaleString()听起来有点像用JavaScript创建一个时钟应用程序,并以这种方式对其进行硬编码,这样它将只显示布拉格时间(这对于不住在布拉格的人来说非常无用),尽管默认行为是

new Date();

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

感谢大家的回复。我总结了一些答案,以制定一个更“一刀切”的解决方案。

第一段代码向number原型添加了一个模仿PHP的number_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将5000转换为5,只需取第一个整数值序列。所以我创建了自己的浮点转换函数,并将其添加到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

通用、快速、准确、功能简单

使用RegEx(快速准确)支持数字(浮点数/整数)/字符串/字符串中的多个数字智能井(不分组小数-兼容不同类型的分组)支持所有浏览器,特别是“Safari”和“IE”以及许多旧浏览器[可选]尊重非英语(波斯语/阿拉伯语)数字(+前缀)

TL;DR-完整版本功能(缩小):

//num:Number/s(字符串/数字),//sep:千位分隔符(字符串)-默认值:','//dec:十进制分隔符(字符串)-默认值:“.”(只有一个字符)//u:对语言字符的通用支持(String-RegEx字符集/类)-示例:“[\\d\\u0660-\\u0669\\u06f0-\\u06f3]”(英语/波斯语/阿拉伯语),默认值:“\\d”(英语)函数格式Nums(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'),函数(a){return a.length==1?a+sep:a})}text='00000000英语或波斯语/阿拉伯语۱1778; 1779; 1780; 1781; 1782; 1783; 1784; 1785;/٠1633; 1634; 1635; 1636; 1637;٦这是123123.123123加上这个-123123和这10 100 1000 123123/12123(2000000)33333 100.00或任何类似的50万千克';console.log(formatNums(10000000.0012));console.log(formatNums(10000000.0012,'.',','));//德国的console.log(formatNums(文本,',','.','[\\d\\u0660-\\u0669\\u06f0-\\u06f4]');//尊重波斯语/阿拉伯数字<input-oninput=“document.getElementById('result').textContent=formatNums(this.value)”placeholder=“在此处键入数字”><div id=“result”></div>

为什么不满意其他答案?

Number.pr原型.toLocaleString()/Intl.NumberFormat(正确答案)若并没有好的论点,我们就不能期待同样的结果。此外,对于参数选项,我们仍然无法确定结果,因为它将使用本地设置和可能的客户端修改效果,或者浏览器/设备不支持它。>~ 2016年的浏览器支持,但到2021,仍有一些报告称,在某些情况下,如Safari或IE/Edge,不会按预期返回。toLocaleString()使用数字,Intl.NumberFormat使用字符串/数字;如果需要,字符串将被解析并舍入,因此:如果我们已经有一个非英文数字的本地化字符串,我们必须用英文数字替换数字,然后解析它,然后使用本地选项再次使用它。(如果它返回我们期望的结果)通常,在解析时,我们不能期望不丢失十进制零或大数字中的细节,也不能期望不尊重其他语言数字字符小数/千位分隔符的自定义不能超过语言选项,除非再次使用replace()+RegEx进行后置固定。(例如,在波斯语中,我们通常不使用建议的阿拉伯逗号,有时我们使用∕分数/除法斜线作为小数分隔符)环路中的性能低下不太好的RegEx方式(最快和一行方式)/\B(?=(\d{3})+\B)/它也会对小数进行分组。//123,123.123,123 !!!/(?<!\.\d+)\B(?=(\d{3})+\B)/使用了尚未很好支持的查找。请检查:https://caniuse.com/js-regexp-lookbehindhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#browser_compatibility注意:一般情况下,lookbacking可能会与原始RegEx结构相违背(因为分析器的工作方式应该像不缓冲原始数据一样),实际上它会使性能严重降低(在本例中约为30%)。我认为这是一段时间以来的要求。/\B(?=(?=\d*\.)(\d{3})+(?!\d))/只处理浮点数,忽略整数。.replace(/(?:[^.\d]|^)\d+/g,函数(a){return a.replace(/\B(?=(?:\d{3})+\B)/g,',');})(我的旧想法)使用2 RegEx。第一个查找整数部分,第二个放置分隔符。为什么可以混合使用两种功能?/(\..*)$|(\d)(?=(\d{3})+(?!\d))/g(@djulien的好主意-我投了赞成票)但当RegEx是全局的时,(\..*$即使最后有空格也可能出错。使用捕获组(例如:(\d))也会降低性能,因此如果可能,请使用非捕获组(示例:(?:\d)或如果函数中已经存在语句,让我们混合使用。在这种情况下,不使用捕获组可以提高约20%的性能,在/\B(?=(\d{3})+\B)/g与/\B?=(?:\d})+/B)/g的情况下,第二个捕获组的速度快约8%。关于正则表达式性能:注意:不同的方法、浏览器、硬件、系统状态、案例甚至ECMAScript上的更改都会影响性能检查结果。但一些逻辑上的改变应该会影响结果,我用这个例子作为视觉示例。使用像Numeral.js这样的库并不是简单任务所必需的函数。重代码/使用.split('.')或.toFixed()或Math.floor()的函数不准确。。。


最终结果:

没有最好的,应该根据需要来选择。我的排序优先级;

兼容性能力普遍性易于使用表演

toLocaleString()(兼容性-通用性)[本机函数]

如果您必须将数字和分组从英语更改为另一种语言如果你不确定你的客户语言如果你不需要确切的预期结果如果你不在乎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

阅读更多信息:https://www.w3schools.com/jsref/jsref_tolocalestring_number.asp

Intl.NumberFormat()(功能-通用性-兼容性)[本机函数]

与toLocaleString()几乎相同+

支持货币、单位等任何语言的强大功能(现代浏览器)

// 1000000.2301
new Intl.NumberFormat('en-US', { // It can be 'fa-IR' : Farsi - Iran
    numberingSystem: 'arab'
}).format(num)
// ١٬٠٠٠٬٠٠٠٫٢٣

阅读更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat

有了这些本机函数选项,我们仍然无法期待:

精确结果(+不解析输入/不舍入/不转换大数字)接受其他语言数字作为输入自定义分隔符信任浏览器支持表演

所以你可能需要一个这样的函数:

formatNums()(兼容性-易于使用)

完整版本(功能)(不快于toLocaleString)-解释:

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.
        })
}

函数格式Nums(num,sep,dec,u){sep=sep||',';u=u||'\\d';if(typeof num!=“字符串”){num=字符串(num);如果(dec&&dec!='.')num=num.replace('.',dec);}return num.replace(RegExp('\\'+(dec||'.')+u+'+|'+u+'(?=(?:'+u+‘{3})+(?!'+u'))','g'),函数(a){return a.length==1?a+sep:a})}console.log(formatNums(100000.2301));console.log(formatNums(100.2301));console.log(formatNums(-2000.2301));console.log(formatNums(123123123,','));console.log(formatNums('0000.000'));console.log(formatNums('50000000.00'));console.log(formatNums('5000000,00','',''));console.log(formatNums(5000000.1234,'',''));console.log(formatNums('۱۲۩۴گܞۏՀۛ/۹ۈ܄\ 1776; \1776;;',','、'、'/'、'[\d\\u0660-\\u0669\\u06f0-\\u069]'));

在这里播放示例:https://jsfiddle.net/PAPIONbit/198xL3te/

轻版本(性能)(比toLocaleString快约30%)

函数格式Nums(num,sep){sep=sep||',';return字符串(num).replace(/\.\d+|\d(?=(?:\d{3})+(?!\d))/g,函数(a){返回a.length==1?a+sep:a});}console.log(formatNums(100000.2301));console.log(formatNums(100.2301));console.log(formatNums(-2000.2301));console.log(formatNums(123123123,''));

检查RegEx(没有必要的功能):https://regexr.com/66ott

(num+'').replace(/\B(?=(?:\d{3})+\B)/g,',');(性能-兼容性)

如果输入为“指定/预定义”,则最佳选择。(和通常的价格一样,肯定不会超过3位小数)(比toLocaleString快约65%)

num=1000000;str='123123.100';console.log((num+'').replace(/\B(?=(?:\d{3})+\B)/g,','));console.log(str.replace(/\B(?=(?:\d{3})+\B)/g,','));

+

对于波斯语/阿拉伯语本地客户:

如果你的客户像在伊朗一样使用波斯语/阿拉伯数字进行输入,我认为最好的方法是不保留原始字符,而是在处理之前将其转换为英语,这样你就可以计算出来。

// ۱۲۳۴۵۶۷۸۹۰
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

为了让它们看起来仍然是原始的,有两种方法:

CSS使用带有本地数字的波斯语/阿拉伯语字体(我选择)使用Intl.NumberFormat或以下函数将结果转换回:https://stackoverflow.com/a/13787021/7514010


我在这篇文章中的老学校函数:(比toLocalString快15%)

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

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

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的一些更正,别忘了对他的评论投赞成票。