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

我是这样做的:

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

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


当前回答

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

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

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-正则表达式查找

其他回答

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

第一段代码向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

使用此代码处理印度的货币格式。可以更改国家/地区代码以处理其他国家/地区货币。

let amount =350256.95
var formatter = new Intl.NumberFormat('en-IN', {
  minimumFractionDigits: 2,
});

// Use it.

formatter.format(amount);

输出:

3,50,256.95

我对这个问题的答案数量印象深刻。我喜欢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)

使用正则表达式

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

使用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.protype.toLocaleString()

使用国际号码格式()

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"

参考Intl.NumberFormat

在这里演示<script type=“text/javascript”>//使用正则表达式函数到逗号(值){return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g,“,”);}函数命令(){var num1=文档.myform.number1.value;//使用正则表达式document.getElementById('result1').value=toCommas(parseInt(num1));//使用toLocaleString()document.getElementById('result2').value=parseInt(num1).toLocaleString('ja-JP'{style:'货币',货币:'日元'});//使用国际号码格式()document.getElementById('result3').value=新Intl.NumberFormat('ja-JP'{style:'货币',货币:'日元'}).格式(num1);}</script><FORM NAME=“myform”><INPUT TYPE=“text”NAME=“number1”VALUE=“123456789”><br><INPUT TYPE=“button”NAME=“button“Value=”=>“onClick=”commas()“><br>使用正则表达式<br><INPUT TYPE=“text”ID=“result1”NAME=“result1”VALUE=“”><br>使用toLocaleString()<br><INPUT TYPE=“text”ID=“result2”NAME=“result2“VALUE=”“><br>使用国际号码格式()<br><INPUT TYPE=“text”ID=“result3”NAME=“result3“VALUE=”“></FORM>表演http://jsben.ch/sifRd

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

第一个代码是这样的。

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