我想用JavaScript格式化价格。我想要一个函数,它将浮点作为参数,并返回如下格式的字符串:
"$ 2,500.00"
我该怎么做?
我想用JavaScript格式化价格。我想要一个函数,它将浮点作为参数,并返回如下格式的字符串:
"$ 2,500.00"
我该怎么做?
当前回答
一个简单的选项,通过先反转字符串和基本正则表达式来正确放置逗号。
String.prototype.reverse = function() {
return this.split('').reverse().join('');
};
Number.prototype.toCurrency = function( round_decimal /*boolean*/ ) {
// format decimal or round to nearest integer
var n = this.toFixed( round_decimal ? 0 : 2 );
// convert to a string, add commas every 3 digits from left to right
// by reversing string
return (n + '').reverse().replace( /(\d{3})(?=\d)/g, '$1,' ).reverse();
};
其他回答
我从accounting.js中找到了这个。它非常简单,非常适合我的需要。
//默认用法:accounting.formatMoney(12345678);//$12,345,678.00//欧洲格式(自定义符号和分隔符),也可以使用options对象作为第二个参数:accounting.formatMoney(4999.99,“€”,2,“.”,“,”);//€4.999,99//负值可以很好地格式化:accounting.formatMoney(-50万,“£”,0);//£ -500,000//简单的“格式”字符串允许控制符号位置(%v=值,%s=符号):accounting.formatMoney(5318008,{符号:“GBP”,格式:“%v%s”});//5318008.00 GBP//右侧的欧元货币符号accounting.formatMoney(5318008,{符号:“€”,精度:2,千:“.”,十进制:“,”,格式:“%v%s”});//1.008,00€
许多答案都有有益的想法,但没有一个能满足我的需求。所以我使用了所有的想法,并构建了这个示例:
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帖子中修改过的想法;很抱歉,我不能引用所有这些,但感谢所有的专家。
以下是将数字转换为货币格式的简短最佳方法:
function toCurrency(amount){
return amount.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
// usage: toCurrency(3939920.3030);
我主要基于VisionN的回答:
function format (val) {
val = (+val).toLocaleString();
val = (+val).toFixed(2);
val += "";
return val.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1" + format.thousands);
}
(function (isUS) {
format.decimal = isUS ? "." : ",";
format.thousands = isUS ? "," : ".";
}(("" + (+(0.00).toLocaleString()).toFixed(2)).indexOf(".") > 0));
我用输入进行了测试:
[ ""
, "1"
, "12"
, "123"
, "1234"
, "12345"
, "123456"
, "1234567"
, "12345678"
, "123456789"
, "1234567890"
, ".12"
, "1.12"
, "12.12"
, "123.12"
, "1234.12"
, "12345.12"
, "123456.12"
, "1234567.12"
, "12345678.12"
, "123456789.12"
, "1234567890.12"
, "1234567890.123"
, "1234567890.125"
].forEach(function (item) {
console.log(format(item));
});
得到了这些结果:
0.00
1.00
12.00
123.00
1,234.00
12,345.00
123,456.00
1,234,567.00
12,345,678.00
123,456,789.00
1,234,567,890.00
0.12
1.12
12.12
123.12
1,234.12
12,345.12
123,456.12
1,234,567.12
12,345,678.12
123,456,789.12
1,234,567,890.12
1,234,567,890.12
1,234,567,890.13
只是为了好玩。
我喜欢VisionN的最短答案,除非我需要修改一个没有小数点的数字(123美元而不是123.00美元)。它不起作用,所以我需要破解JavaScript正则表达式的神秘语法,而不是快速复制/粘贴。
这是最初的解决方案
n.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
我会再延长一点:
var re = /\d(?=(\d{3})+\.)/g;
var subst = '$&,';
n.toFixed(2).replace(re, subst);
此处的re部分(字符串替换中的搜索部分)表示
查找所有数字(\d)后跟(?=…)(展望)一个或多个组(…)+正好三位数(\d{3})以点(\.)结尾对所有事件执行此操作(g)
这里的子部分是指:
每次有匹配项时,将其替换为自身($&),后跟逗号。
当我们使用string.replace时,字符串中的所有其他文本保持不变,只有找到的数字(后面跟着3、6、9等其他数字的数字)才会得到一个额外的逗号。
因此,在数字1234567.89中,数字1和4满足条件(1234567.89),并被替换为“1”和“4”,从而得到1234567.89。
如果我们根本不需要美元金额的小数点(即123美元而不是123.00美元),我们可以这样更改正则表达式:
var re2 = /\d(?=(\d{3})+$)/g;
它依赖于行尾($)而不是点(\.),最后的表达式将是(请注意Fixed(0)):
n.toFixed(0).replace(/\d(?=(\d{3})+$)/g, '$&,');
此表达式将给出
1234567.89 -> 1,234,567
此外,您也可以选择单词边界(\b),而不是上面正则表达式中的行尾($)。
如果我误解了正则表达式处理的任何部分,我会提前道歉。