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

我是这样做的:

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

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


当前回答

我使用了克里的答案中的想法,但简化了它,因为我只是在为我的特定目的寻找简单的东西。以下是我所拥有的:

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

函数编号WithCommas(x){return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g,“,”);}功能测试(x,预期){常量结果=带逗号的数字(x);常量pass=result==预期;console.log(`${pass?”✓“:”错误===>“}${x}=>${result}`);回传;}让失败=0;失败+=!测试(0,“0”);失败+=!测试(100,“100”);失败+=!测试(1000,“1000”);失败+=!测试(10000,“10000”);失败+=!测试(100000,“100000”);失败+=!测试(1000000,“1000000”);失败+=!测试(10000000,“10000000”);if(失败){console.log(“${failures}测试失败”);}其他{console.log(“所有测试均通过”);}.作为控制台包装{最大高度:100%!重要的}


正则表达式使用2个前瞻断言:

一个正数用于查找字符串中其后一行中具有3位数倍数的任何点,一个否定断言,以确保该点只有3位数的倍数。替换表达式在此处放置逗号。

例如,如果您传递它123456789.01,则肯定断言将匹配7左边的每个点(因为789是3位数的倍数,678是3位的倍数,567等)。否定断言检查3位数的乘数后面没有任何数字。789后面有一个句点,所以它正好是3位数字的倍数,所以在那里有一个逗号。678是3位数的倍数,但后面有一个9,所以这3位数是4位数的一部分,逗号不在那里。567也是如此。456789是6位数字,是3的倍数,所以前面是逗号。345678是3的倍数,但后面有一个9,所以没有逗号。以此类推。\B防止正则表达式在字符串的开头加逗号。

@neu-rah提到,如果小数点后有超过3位数字,则该函数会在不需要的地方添加逗号。如果这是一个问题,您可以使用此函数:

function numberWithCommas(x) {
    var parts = x.toString().split(".");
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    return parts.join(".");
}

函数编号WithCommas(x){var parts=x.toString().split(“.”);parts[0]=parts[0]。替换(/\B(?=(\d{3})+(?!\d))/g,“,”);return parts.join(“.”);}功能测试(x,预期){常量结果=带逗号的数字(x);常量pass=result==预期;console.log(`${pass?”✓“:”错误===>“}${x}=>${result}`);回传;}让失败=0;失败+=!测试(0,“0”);失败+=!测试(0.123456,“0.123456”);失败+=!测试(100,“100”);失败+=!测试(100.123456,“100.123456”);失败+=!测试(1000,“1000”);失败+=!测试(1000-123456,“1000-123456”);失败+=!测试(10000,“10000”);失败+=!测试(10000.123456,“10000.123454”);失败+=!测试(100000,“100000”);失败+=!测试(100000.123456,“10000.123456”);失败+=!测试(1000000,“1000000”);失败+=!测试(1000000123456,“1000000123446”);失败+=!测试(10000000,“10000000”);失败+=!测试(10000000.123456,“10000000.123454”);if(失败){console.log(“${failures}测试失败”);}其他{console.log(“所有测试均通过”);}.作为控制台包装{最大高度:100%!重要的}

@t.j.crowder指出,现在JavaScript有了lookbacking(支持信息),它可以在正则表达式本身中解决:

function numberWithCommas(x) {
    return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
}

函数编号WithCommas(x){return x.toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g,“,”);}功能测试(x,预期){常量结果=带逗号的数字(x);常量pass=result==预期;console.log(`${pass?”✓“:”错误===>“}${x}=>${result}`);回传;}让失败=0;失败+=!测试(0,“0”);失败+=!测试(0.123456,“0.123456”);失败+=!测试(100,“100”);失败+=!测试(100.123456,“100.123456”);失败+=!测试(1000,“1000”);失败+=!测试(1000-123456,“1000-123456”);失败+=!测试(10000,“10000”);失败+=!测试(10000.123456,“10000.123454”);失败+=!测试(100000,“100000”);失败+=!测试(100000.123456,“10000.123456”);失败+=!测试(1000000,“1000000”);失败+=!测试(1000000123456,“1000000123446”);失败+=!测试(10000000,“10000000”);失败+=!测试(10000000.123456,“10000000.123454”);if(失败){console.log(“${failures}测试失败”);}其他{console.log(“所有测试均通过”);}.作为控制台包装{最大高度:100%!重要的}

(?<!\.\d*)是一个表示匹配前面不能有。后跟零个或多个数字。至少在V8中,反向查找比拆分和连接解决方案(比较)更快。

其他回答

另一种复杂度为n(数学楼层(str.length/3))而不是n(str.lngth)的方法

function formatNumber(num) {
  let str = String(num)
  
  if (num < 1000) return str

  let result = ''

  for (let i = Math.floor(str.length / 3); i >= 0; i--) {
    let start = str.length - 3 * (i + 1)
    let end = start + 3

    result +=
      (end ? str.slice(Math.max(0, start), end) : '') + (end && i ? ',' : '')
  }

  return result
}

我已经调整了您的代码以在TextBox(输入类型=“text”)中工作,这样我们就可以在不丢失光标的情况下实时输入和删除数字。如果您在删除时选择范围,它也会起作用。您可以自由使用箭头和起始/结束按钮。谢谢你节省了我的时间!

//function controls number format as "1,532,162.3264321"
function numberWithCommas(x) {
    var e = e || window.event;
    if (e.keyCode >= '35' && e.keyCode <= '40') return; //skip arrow-keys
    var selStart = x.selectionStart, selEnd = x.selectionEnd; //save cursor positions
    var parts = x.value.toString().split(".");
    var part0len = parts[0].length; //old length to check if new ',' would be added. Need for correcting new cursor position (+1 to right).

    //if user deleted ',' - remove previous number instead (without selection)
    if (x.selectionLength == 0 && (e.keyCode == 8 || e.keyCode == 46)) {//if pressed 8-backspace or 46-delete button
        var delPos = parts[0].search(/\d{4}/);
        if (delPos != -1) {//if found 4 digits in a row (',' is deleted)
            if (e.keyCode == 8) {//if backspace flag
                parts[0] = parts[0].slice(0, selStart - 1) + parts[0].slice(selEnd, parts[0].length);
                selEnd--;
                if (selStart > selEnd) selStart = selEnd;
            } else {
                parts[0] = parts[0].slice(0, selStart) + parts[0].slice(selEnd + 1, parts[0].length);
                selStart++;
                if (selEnd < selStart) selEnd = selStart;
            }
        }
    }

   var hasMinus = parts[0][0] == '-';
   parts[0] = (hasMinus ? '-' : '') + parts[0].replace(/[^\d]*/g, ""); //I'd like to clear old ',' to avoid things like 1,2,3,5,634.443216
   parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); //sets ',' between each 3 digits
   if (part0len < parts[0].length) { //move cursor to right if added new ','
       selStart++;
       selEnd++;
   } else if (part0len > parts[0].length) { //..or if removed last one ','
       selStart--;
       selEnd--;
   }
   x.value = parts.join(".");
   x.setSelectionRange(selStart, selEnd); //restoring cursor position
}
function saveSelectionLength(x) {
    x.selectionLength = x.selectionEnd - x.selectionStart;
}

要使用它,只需添加两个事件-onKeyUp和onKeyDown

<asp:TextBox runat="server" ID="val" Width="180px" onKeyUp="numberWithCommas(this);" onKeyDown="saveSelectionLength(this);"/>
let formatNumber = (number) => {
    let str = String(number)

    return str.split('').reduce(
        (a, b, i) => a + (i && !((str.length - i) % 3) ? ',' : '') + b,
        ''
    )
}

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

我认为该功能将处理与此问题相关的所有问题。

function commaFormat(inputString) {
    inputString = inputString.toString();
    var decimalPart = "";
    if (inputString.indexOf('.') != -1) {
        //alert("decimal number");
        inputString = inputString.split(".");
        decimalPart = "." + inputString[1];
        inputString = inputString[0];
        //alert(inputString);
        //alert(decimalPart);

    }
    var outputString = "";
    var count = 0;
    for (var i = inputString.length - 1; i >= 0 && inputString.charAt(i) != '-'; i--) {
        //alert("inside for" + inputString.charAt(i) + "and count=" + count + " and outputString=" + outputString);
        if (count == 3) {
            outputString += ",";
            count = 0;
        }
        outputString += inputString.charAt(i);
        count++;
    }
    if (inputString.charAt(0) == '-') {
        outputString += "-";
    }
    //alert(outputString);
    //alert(outputString.split("").reverse().join(""));
    return outputString.split("").reverse().join("") + decimalPart;
}