我想用JavaScript格式化价格。我想要一个函数,它将浮点作为参数,并返回如下格式的字符串:

"$ 2,500.00"

我该怎么做?


当前回答

PHP函数“number_format”有一个JavaScript端口。

我发现它非常有用,因为它易于使用,并且对PHP开发人员来说是可识别的。

function number_format (number, decimals, dec_point, thousands_sep) {
    var n = number, prec = decimals;

    var toFixedFix = function (n,prec) {
        var k = Math.pow(10,prec);
        return (Math.round(n*k)/k).toString();
    };

    n = !isFinite(+n) ? 0 : +n;
    prec = !isFinite(+prec) ? 0 : Math.abs(prec);
    var sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
    var dec = (typeof dec_point === 'undefined') ? '.' : dec_point;

    var s = (prec > 0) ? toFixedFix(n, prec) : toFixedFix(Math.round(n), prec);
    // Fix for Internet Explorer parseFloat(0.55).toFixed(0) = 0;

    var abs = toFixedFix(Math.abs(n), prec);
    var _, i;

    if (abs >= 1000) {
        _ = abs.split(/\D/);
        i = _[0].length % 3 || 3;

        _[0] = s.slice(0,i + (n < 0)) +
               _[0].slice(i).replace(/(\d{3})/g, sep+'$1');
        s = _.join(dec);
    } else {
        s = s.replace('.', dec);
    }

    var decPos = s.indexOf(dec);
    if (prec >= 1 && decPos !== -1 && (s.length-decPos-1) < prec) {
        s += new Array(prec-(s.length-decPos-1)).join(0)+'0';
    }
    else if (prec >= 1 && decPos === -1) {
        s += dec+new Array(prec).join(0)+'0';
    }
    return s;
}

(原文注释栏,包括以下示例和到期信用)

// Formats a number with grouped thousands
//
// version: 906.1806
// discuss at: http://phpjs.org/functions/number_format
// +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// +     bugfix by: Michael White (http://getsprink.com)
// +     bugfix by: Benjamin Lupton
// +     bugfix by: Allan Jensen (http://www.winternet.no)
// +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
// +     bugfix by: Howard Yeend
// +    revised by: Luke Smith (http://lucassmith.name)
// +     bugfix by: Diogo Resende
// +     bugfix by: Rival
// +     input by: Kheang Hok Chin (http://www.distantia.ca/)
// +     improved by: davook
// +     improved by: Brett Zamir (http://brett-zamir.me)
// +     input by: Jay Klehr
// +     improved by: Brett Zamir (http://brett-zamir.me)
// +     input by: Amir Habibi (http://www.residence-mixte.com/)
// +     bugfix by: Brett Zamir (http://brett-zamir.me)
// *     example 1: number_format(1234.56);
// *     returns 1: '1,235'
// *     example 2: number_format(1234.56, 2, ',', ' ');
// *     returns 2: '1 234,56'
// *     example 3: number_format(1234.5678, 2, '.', '');
// *     returns 3: '1234.57'
// *     example 4: number_format(67, 2, ',', '.');
// *     returns 4: '67,00'
// *     example 5: number_format(1000);
// *     returns 5: '1,000'
// *     example 6: number_format(67.311, 2);
// *     returns 6: '67.31'
// *     example 7: number_format(1000.55, 1);
// *     returns 7: '1,000.6'
// *     example 8: number_format(67000, 5, ',', '.');
// *     returns 8: '67.000,00000'
// *     example 9: number_format(0.9, 0);
// *     returns 9: '1'
// *     example 10: number_format('1.20', 2);
// *     returns 10: '1.20'
// *     example 11: number_format('1.20', 4);
// *     returns 11: '1.2000'
// *     example 12: number_format('1.2000', 3);
// *     returns 12: '1.200'

其他回答

许多答案都有有益的想法,但没有一个能满足我的需求。所以我使用了所有的想法,并构建了这个示例:

function Format_Numb(fmt){
    var decimals = isNaN(decimals) ? 2 : Math.abs(decimals);
    if(typeof decSgn === "undefined") decSgn = ".";
    if(typeof kommaSgn === "undefined") kommaSgn= ",";

    var s3digits = /(\d{1,3}(?=(\d{3})+(?=[.]|$))|(?:[.]\d*))/g;
    var dflt_nk = "00000000".substring(0, decimals);

    //--------------------------------
    // handler for pattern: "%m"
    var _f_money = function(v_in){
                       var v = v_in.toFixed(decimals);
                       var add_nk = ",00";
                       var arr = v.split(".");
                       return arr[0].toString().replace(s3digits, function ($0) {
                           return ($0.charAt(0) == ".")
                                   ? ((add_nk = ""), (kommaSgn + $0.substring(1)))
                                   : ($0 + decSgn);
                           })
                           + ((decimals > 0)
                                 ? (kommaSgn
                                       + (
                                           (arr.length > 1)
                                           ? arr[1]
                                           : dflt_nk
                                       )
                                   )
                                 : ""
                           );
                   }

    // handler for pattern: "%<len>[.<prec>]f"
    var _f_flt = function(v_in, l, prec){
        var v = (typeof prec !== "undefined") ? v_in.toFixed(prec) : v_in;
        return ((typeof l !== "undefined") && ((l=l-v.length) > 0))
                ? (Array(l+1).join(" ") + v)
                : v;
    }

    // handler for pattern: "%<len>x"
    var _f_hex = function(v_in, l, flUpper){
        var v = Math.round(v_in).toString(16);
        if(flUpper) v = v.toUpperCase();
        return ((typeof l !== "undefined") && ((l=l-v.length) > 0))
                ? (Array(l+1).join("0") + v)
                : v;
    }

    //...can be extended..., just add the function, for example:    var _f_octal = function( v_in,...){
    //--------------------------------

    if(typeof(fmt) !== "undefined"){
        //...can be extended..., just add the char, for example "O":    MFX -> MFXO
        var rpatt = /(?:%([^%"MFX]*)([MFX]))|(?:"([^"]*)")|("|%%)/gi;
        var _qu = "\"";
        var _mask_qu = "\\\"";
        var str = fmt.toString().replace(rpatt, function($0, $1, $2, $3, $4){
                      var f;
                      if(typeof $1 !== "undefined"){
                          switch($2.toUpperCase()){
                              case "M": f = "_f_money(v)";    break;

                              case "F": var n_dig0, n_dig1;
                                        var re_flt =/^(?:(\d))*(?:[.](\d))*$/;
                                        $1.replace(re_flt, function($0, $1, $2){
                                            n_dig0 = $1;
                                            n_dig1 = $2;
                                        });
                                        f = "_f_flt(v, " + n_dig0 + "," + n_dig1 + ")";    break;

                              case "X": var n_dig = "undefined";
                                        var re_flt = /^(\d*)$/;
                                        $1.replace(re_flt, function($0){
                                            if($0 != "") n_dig = $0;
                                        });
                                        f = "_f_hex(v, " + n_dig + "," + ($2=="X") + ")";    break;
                              //...can be extended..., for example:    case "O":
                          }
                          return "\"+"+f+"+\"";
                      } else if(typeof $3 !== "undefined"){
                          return _mask_qu + $3 + _mask_qu;
                      } else {
                          return ($4 == _qu) ? _mask_qu : $4.charAt(0);
                      }
                  });

        var cmd =     "return function(v){"
                +     "if(typeof v === \"undefined\")return \"\";"  // null returned as empty string
                +     "if(!v.toFixed) return v.toString();"         // not numb returned as string
                +     "return \"" + str + "\";"
                + "}";

        //...can be extended..., just add the function name in the 2 places:
        return new Function("_f_money,_f_flt,_f_hex", cmd)(_f_money,_f_flt,_f_hex);
    }
}

首先,我需要一个C样式格式的字符串定义,它应该是灵活的,但非常容易使用,我用以下方式定义它:;模式:

%[<len>][.<prec>]f   float, example "%f", "%8.2d", "%.3f"
%m                   money
%[<len>]x            hexadecimal lower case, example "%x", "%8x"
%[<len>]X            hexadecimal upper case, example "%X", "%8X"

因为对我来说,除了欧元之外,没有任何其他格式的需要,所以我只实现了“%m”。

但这很容易扩展。。。与C中一样,格式字符串是包含模式的字符串。例如,对于欧元:“%m€”(返回类似“8.129,33€”的字符串)

除了灵活性之外,我还需要一个处理表的快速解决方案。这意味着,在处理数千个单元格时,格式字符串的处理不能重复一次。我不接受类似“format(value,fmt)”的调用,但这必须分为两个步骤:

// var formatter = Format_Numb( "%m €");
// simple example for Euro...

//   but we use a complex example:

var formatter = Format_Numb("a%%%3mxx \"zz\"%8.2f°\"  >0x%8X<");

// formatter is now a function, which can be used more than once (this is an example, that can be tested:)

var v1 = formatter(1897654.8198344);

var v2 = formatter(4.2);

... (and thousands of rows)

同样为了提高性能,_f_money包含正则表达式;

第三,类似“format(value,fmt)”的调用是不可接受的,因为:

虽然可以用不同的掩码格式化不同的对象集合(例如,列的单元格),但我不想在处理时处理格式化字符串。此时,我只想使用格式,如

for(单元格中的var单元格){do_something(cell.col.formatter(cell.value));}

什么格式-可能是在.ini文件中,在XML中为每一列或其他地方定义的。。。,但是分析和设置格式或处理国际化完全是在另一个地方进行的,在那里我想将格式化程序分配给集合,而不考虑性能问题:

col.formatter=格式_字符串(_getFormatForColumn(…));

第四,我想要一个“宽容”的解决方案,因此传递例如字符串而不是数字应该只返回字符串,但“null”应该返回一个空字符串。

(如果值太大,格式化“%4.2f”也不能剪切。)

最后,但并非最不重要的是,它应该是可读的,易于扩展,而不会对性能产生任何影响。。。例如,如果某人需要“八进制值”,请参考带有“…可以扩展…”的行-我认为这应该是一项非常简单的任务。

我的整体重点是表现。每个“处理例程”(例如,_f_money)都可以被封装优化,或者在这个或其他线程中与其他思想进行交换,而无需更改“准备例程”(分析格式字符串和创建函数),这些例程只能被处理一次,从这个意义上说,与数千个数字的转换调用相比,性能并不那么关键。

对于所有喜欢数字方法的人来说:

Number.prototype.format_euro = (function(formatter){
    return function(){ return formatter(this); }})
(Format_Numb( "%m €"));

var v_euro = (8192.3282).format_euro(); // results: 8.192,33 €

Number.prototype.format_hex = (function(formatter){
    return function(){ return formatter(this); }})
(Format_Numb( "%4x"));

var v_hex = (4.3282).format_hex();

虽然我测试了一些,但代码中可能有很多错误。因此,它不是一个现成的模块,只是像我这样的非JavaScript专家的一个想法和起点。

该代码包含了许多StackOverflow帖子中修改过的想法;很抱歉,我不能引用所有这些,但感谢所有的专家。

数字.原型.固定

此解决方案与每个主要浏览器都兼容:

  const profits = 2489.8237;

  profits.toFixed(3) // Returns 2489.824 (rounds up)
  profits.toFixed(2) // Returns 2489.82
  profits.toFixed(7) // Returns 2489.8237000 (pads the decimals)

您只需添加货币符号(例如“$”+利润.toFixed(2)),即可获得美元金额。

自定义函数

如果需要在每个数字之间使用,则可以使用此函数:

函数格式Money(number,decPlaces,decSep,thouSep){decPlaces=isNaN(decPlaces=数学.abs(decPlaces))?2:decPlaces,decSep=decSep的类型==“未定义”?“.”:12月9日;thouSep=thouSep==“未定义”的类型?“,”:thouSep;var符号=数字<0?"-" : "";var i=字符串(parseInt(number=Math.abs(number(number)||0).toFixed(decPlaces)));变量j=(j=i.length)>3?j%3:0;返回标志+(j?i.substr(0,j)+thouSep:“”)+i.substr(j).replace(/(\decSep{3})(?=\decSep)/g,“$1”+thouSep)+(decPlaces?decSep+Math.abs(数字-i).toFixed(decPlace).slice(2):“”);}document.getElementById(“b”).addEventListener(“单击”,event=>{document.getElementById(“x”).innerText=“结果为:”+formatMoney(document.getElement ById(”d“).value);});<label>插入您的金额:<input id=“d”type=“text”placeholder=“Cash amount”/></label><br/><button id=“b”>获取输出</button><p id=“x”>(按下按钮获取输出)</p>

这样使用:

(123456789.12345).formatMoney(2, ".", ",");

如果你总是使用“.”和',',您可以将它们从方法调用中删除,方法将为您默认它们。

(123456789.12345).formatMoney(2);

如果您的文化中有两个符号翻转(即,欧洲人),并且您希望使用默认值,只需在formatMoney方法中粘贴以下两行:

    d = d == undefined ? "," : d,
    t = t == undefined ? "." : t,

自定义功能(ES6)

如果您可以使用现代ECMAScript语法(即,通过Babel),则可以使用更简单的函数:

函数formatMoney(amount,decimalCount=2,decimal=“.”,千=“,”){尝试{decimalCount=数学.abs(decimalCount);decimalCount=isNaN(decimalCount)?2:小数计数;常量负符号=金额<0?"-" : "";让i=parseInt(amount=Math.abs(Number(amount)||0).toFixed(decimalCount)).toString();设j=(i.length>3)?i.长度%3:0;回来否定符号+(j?i.substr(0,j)+千:“”)+i.substr(j).replace(/(\d{3})(?=\d)/g,“$1”+千)+(decimalCount?decimal+Math.abs(amount-i).toFixed(decimalCount).slice(2):“”);}捕获(e){控制台日志(e)}};document.getElementById(“b”).addEventListener(“单击”,event=>{document.getElementById(“x”).innerText=“结果为:”+formatMoney(document.getElement ById(”d“).value);});<label>插入您的金额:<input id=“d”type=“text”placeholder=“Cash amount”/></label><br/><button id=“b”>获取输出</button><p id=“x”>(按下按钮获取输出)</p>

这可能奏效:

function format_currency(v, number_of_decimals, decimal_separator, currency_sign){
  return (isNaN(v)? v : currency_sign + parseInt(v||0).toLocaleString() + decimal_separator + (v*1).toFixed(number_of_decimals).slice(-number_of_decimals));
}

没有循环,没有正则表达式,没有数组,没有奇异条件。

快速快捷的解决方案(适用于任何地方!)

(12345.67).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');  // 12,345.67

此解决方案背后的思想是用第一个匹配和逗号替换匹配的部分,即“$&,”。匹配是使用前瞻方法完成的。您可以将表达式读为“匹配一个数字,如果它后面跟着三个数字集(一个或多个)和一个点的序列”。

测验:

1        --> "1.00"
12       --> "12.00"
123      --> "123.00"
1234     --> "1,234.00"
12345    --> "12,345.00"
123456   --> "123,456.00"
1234567  --> "1,234,567.00"
12345.67 --> "12,345.67"

演示:http://jsfiddle.net/hAfMM/9571/


扩展短解决方案

您还可以扩展Number对象的原型,以添加对任意数量的小数[0..n]和数字组大小[0..x]的额外支持:

/**
 * Number.prototype.format(n, x)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of sections
 */
Number.prototype.format = function(n, x) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')';
    return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&,');
};

1234..format();           // "1,234"
12345..format(2);         // "12,345.00"
123456.7.format(3, 2);    // "12,34,56.700"
123456.789.format(2, 4);  // "12,3456.79"

演示/测试:http://jsfiddle.net/hAfMM/435/


超扩展短解决方案

在此超级扩展版本中,您可以设置不同的分隔符类型:

/**
 * Number.prototype.format(n, x, s, c)
 * 
 * @param integer n: length of decimal
 * @param integer x: length of whole part
 * @param mixed   s: sections delimiter
 * @param mixed   c: decimal delimiter
 */
Number.prototype.format = function(n, x, s, c) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
        num = this.toFixed(Math.max(0, ~~n));

    return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
};

12345678.9.format(2, 3, '.', ',');  // "12.345.678,90"
123456.789.format(4, 4, ' ', ':');  // "12 3456:7890"
12345678.9.format(0, 3, '-');       // "12-345-679"

演示/测试:http://jsfiddle.net/hAfMM/612/

JavaScript中有一个内置函数toFixed:

var num = new Number(349);
document.write("$" + num.toFixed(2));