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

我是这样做的:

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

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


当前回答

如果所有浏览器(Safari)都提供Number.protype.toLocaleString(),那么它将非常棒。

我检查了所有其他答案,但似乎没有人多填它。这里有一个poc,实际上是前两个答案的组合;如果toLocaleString工作,它会使用它,如果不工作,则使用自定义函数。

var putThousandsSeparators;putThousandsSeparators=函数(值,sep){如果(sep==null){sep=',';}//检查是否需要格式化if(value.toString()==value.toLocaleString()){//分裂小数var parts=value.toString().split('.')//格式化整数parts[0]=parts[0]。替换(/\B(?=(\d{3})+(?!\d))/g,sep);//把它们放回一起值=部件[1]?parts.join('.'):parts[0];}其他{value=value.toLocaleString();}返回值;};警报(putThousandsSeparators(1234567.890));

其他回答

我提出了另一个解决方案。

第一个代码是这样的。

function formatNumber(number) {
  if (number < 1000) {
    return String(number);
  }
  if (number < 1000000) {
    let numbers = String(number).split('');
    numbers.splice(-3, 0, ',');
    return numbers.join('');
  }
  if (number < 1000000000) {
    let numbers = String(number).split('');
    numbers.splice(-3, 0, ',');
    numbers.splice(-7, 0, ',');
    return numbers.join('');
  }
  if (number < 1000000000000) {
    let numbers = String(number).split('');
    numbers.splice(-3, 0, ',');
    numbers.splice(-7, 0, ',');
    numbers.splice(-11, 0, ',');
    return numbers.join('');
  }

  throw new Error(`number: ${number} is too big`);
}

这段代码很长,不可伸缩,但它很有效,因为它检查的是数字本身,而不是从数字转换的字符串的长度。

所以我基于这个想法转换成了整洁的代码。(你可以再放大12个以防出错。)

function formatNumber(number) {
  let commas = -1;
  for (let n3 = 3; n3 <= 12; n3 += 3) {
    commas++;
    const max = Math.pow(10, n3);
    if (number < max) {
      let numbers = String(number).split('');
      for (let i = 0; i < commas; i++) {
        numbers.splice(-(3 * (i + 1) + i), 0, ',');
      }
      return numbers.join('');
    }
  }

  throw new Error(`number: ${number} is too big`);
}

我建议使用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%!重要的}

我的“真正”正则表达式唯一的解决方案

你看到上面那些热情的球员了吗?也许你可以打高尔夫球,这是我的击球。

n => `${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " ").replace(/(?<=\.(\d{3})+)\B/g, " ")

使用 如国际单位制在其出版物《国际单位制手册:国际单位制(SI)》(见§5.3.4.)第八版(2006年)中所说,千位分隔符的空格(U+2009)。第九版(2019年)建议使用空格(见§5.4.4.)。你可以使用任何你想要的东西,包括逗号。


See.

const integer_part_only=n=>`${n}`.replace(/(?<!\.\d+)\B(?=(\d{3})+\B)/g,“I”);const fractional_part_only=n=>`${n}`替换(/(?<=\.(\d{3})+)\B/g,“F”);const both=n=>仅分数部分(整数部分(n));功能演示(编号){//我正在使用Chrome 74。console.log(`${number}→ “${integer_part_only(number)}”(仅整数部分)→ “${fractional_part_only(数字)}”(仅分数部分)→ “${both(number)}”(both)`);}演示(Math.random()*10e5);演示(123456789.01234567);演示(123456789);演示(0.0123456789);


它是如何工作的?

对于整数部分

.replace(/(?<!\.\d+)\B(?=(\d{3})+\b)/g, " I ")

.替换(……,“I”)放入“I”/……/克\B两个相邻数字之间(?=……)右侧部分为(\d{3})+一个或多个三位数块\b后跟非数字,例如句点、字符串结尾等,(?<!……)负外观,不包括其左侧部分\.\d+是一个后跟数字的点(“有一个小数分隔符”)。

对于小数部分

.replace(/(?<=\.(\d{3})+)\B/g, " F ")

.替换(……,“F”)放入“F”/……/克\B两个相邻数字之间(?<=……)左半部分为\. 十进制分隔符(\d{3})+后跟一个或多个三位数块。


字符类和边界

\d)匹配任何数字(阿拉伯数字)。相当于[0-9]。例如/\d/或/[0-9]/匹配B2中的2是组号。\b级匹配单词边界。这是一个单词字符后面或前面没有其他单词字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的单词边界。换句话说,匹配单词边界的长度为零。示例:/\bm/匹配月亮中的m;/oo\b/与moon中的oo不匹配,因为oo后面跟着n,n是一个单词字符;/oon \b/匹配moon中的oon,因为oon是字符串的结尾,因此后面不跟单词字符;/\w\b/w/将永远不会匹配任何内容,因为单词字符后面永远不能同时跟有非单词和单词字符。\B级匹配非单词边界。这是上一个字符和下一个字符类型相同的位置:要么两者都必须是单词,要么两者都是非单词。例如两个字母之间或两个空格之间。字符串的开头和结尾被视为非单词。与匹配的单词边界相同,匹配的非单词边界也不包括在匹配中。例如/\中午开始比赛;/你昨天可能和你比赛。


浏览器兼容性

https://caniuse.com/#feat=js-正则表达式查找

我对这个问题的答案数量印象深刻。我喜欢uKolka的回答:

n.toLocaleString()

但不幸的是,在西班牙语等一些地区,它并不能像预期的那样工作(IMHO):

Number(1000).toLocaleString('ES-es')

给出1000而不是1.000。

请参阅所有浏览器中不能处理小于10000的数字的LocaleString,了解原因。

因此,我不得不使用Elias Zamaria选择正确的千位分隔符的答案:

n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))

对于使用或的两个语言环境,这一行程序都可以很好地作为一行程序使用。在所有情况下,从1000开始工作。

Number(1000).toString().replace(/\B(?=(\d{3})+(?!\d))/g, Number(10000).toLocaleString().substring(2, 3))

给出1.000的西班牙语区域设置上下文。

如果您想对数字的格式进行绝对控制,也可以尝试以下操作:

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)

给出1234.57。

这个不需要正则表达式。它的工作原理是先用toFixed将数字调整到所需的小数位数,然后将其除以小数点。如果有的话。然后将左侧转换为一个数字数组,该数组被反转。然后,从开头开始每三位数字添加一个千位分隔符,结果再次反转。最终的结果是两部分的结合。首先用Math.abs去掉输入数字的符号,必要时再放回去。

它不是一个线性函数,但长度不长,很容易转化为函数。为了清楚起见,添加了变量,但如果事先知道,可以用它们的期望值替换这些变量。您可以使用使用toLocaleString的表达式来查找当前区域设置的小数点和千位分隔符的正确字符(请记住,这些字符需要更现代的Javascript)

在这里没有找到一个现代和全面的解决方案之后,我编写了一个箭头函数(没有正则表达式)来解决格式化问题,它允许调用者为欧洲和世界其他地区提供小数位数以及句点和千位分隔符。

示例:数字格式化程序(1234567890.123456)=>1234567890数字格式化程序(1234567890.123456,4)=>1234567890.1235numberFormatter(1234567890.123456,4,'.',',')=>1.234.567.8901235欧洲

以下是用ES6(现代语法)编写的函数:

const numberFormatter = (number, fractionDigits = 0, thousandSeperator = ',', fractionSeperator = '.') => {
    if (number!==0 && !number || !Number.isFinite(number)) return number
    const frDigits = Number.isFinite(fractionDigits)? Math.min(Math.max(fractionDigits, 0), 7) : 0
    const num = number.toFixed(frDigits).toString()

    const parts = num.split('.')
    let digits = parts[0].split('').reverse()
    let sign = ''
    if (num < 0) {sign = digits.pop()}
    let final = []
    let pos = 0

    while (digits.length > 1) {
        final.push(digits.shift())
        pos++
        if (pos % 3 === 0) {final.push(thousandSeperator)}
    }
    final.push(digits.shift())
    return `${sign}${final.reverse().join('')}${frDigits > 0 ? fractionSeperator : ''}${frDigits > 0 && parts[1] ? parts[1] : ''}`
}

它已被测试为阴性、不良输入和NaN病例。如果输入是NaN,则只需返回它。