如何将数字格式化为货币字符串?

我想用 JavaScript 格式化价格。我想要一个以float作为参数并返回格式如下的string的函数:

"$ 2,500.00"

最好的方法是什么?

答案

Number.prototype.toFixed

该解决方案与每个主流浏览器兼容:

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)

您只需要添加货币符号(例如"$" + profits.toFixed(2) ),您便可以用美元表示金额。

自定义功能

如果你需要使用的,每个数字之间,您可以使用此功能:

function formatMoney(number, decPlaces, decSep, thouSep) {
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces,
decSep = typeof decSep === "undefined" ? "." : decSep;
thouSep = typeof thouSep === "undefined" ? "," : thouSep;
var sign = number < 0 ? "-" : "";
var i = String(parseInt(number = Math.abs(Number(number) || 0).toFixed(decPlaces)));
var j = (j = i.length) > 3 ? j % 3 : 0;

return sign +
	(j ? i.substr(0, j) + thouSep : "") +
	i.substr(j).replace(/(\decSep{3})(?=\decSep)/g, "$1" + thouSep) +
	(decPlaces ? decSep + Math.abs(number - i).toFixed(decPlaces).slice(2) : "");
}

document.getElementById("b").addEventListener("click", event => {
  document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>

像这样使用它:

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

如果您总是要使用 '。和',',您可以将它们保留在方法调用之外,该方法将为您默认它们。

(123456789.12345).formatMoney(2);

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

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

自定义功能(ES6)

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

function formatMoney(amount, decimalCount = 2, decimal = ".", thousands = ",") {
  try {
    decimalCount = Math.abs(decimalCount);
    decimalCount = isNaN(decimalCount) ? 2 : decimalCount;

    const negativeSign = amount < 0 ? "-" : "";

    let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
    let j = (i.length > 3) ? i.length % 3 : 0;

    return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
  } catch (e) {
    console.log(e)
  }
};
document.getElementById("b").addEventListener("click", event => {
  document.getElementById("x").innerText = "Result was: " + formatMoney(document.getElementById("d").value);
});
<label>Insert your amount: <input id="d" type="text" placeholder="Cash amount" /></label>
<br />
<button id="b">Get Output</button>
<p id="x">(press button to get output)</p>

快速简便的解决方案(无处不在!)

(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 具有数字格式化程序(国际化 API 的一部分)。

// Create our number formatter.
var formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD',
});

formatter.format(2500); /* $2,500.00 */

JS 小提琴

使用undefined代替第一个参数(在示例中为'en-US' )以使用系统语言环境(如果代码在浏览器中运行,则为用户语言环境)。

这是货币代码 列表,这是两个字符国家代码列表 (例如,“en-US” 中 “US” 的定义)。

Intl.NumberFormat 与 Number.prototype.toLocaleString

最后一点,将其与较旧版本进行比较。 toLocaleString 。它们都提供基本相同的功能。但是,toLocaleString 的较旧版本(pre-Intl) 实际上并不支持语言环境 :它使用系统语言环境。因此,请确保使用正确的版本( MDN 建议检查是否存在Intl )。同样,对于单个项目,两者的性能相同,但是如果要格式化的数字很多,则使用Intl.NumberFormat会快 70 倍。这是使用toLocaleString

(2500).toLocaleString('en-US', {
  style: 'currency',
  currency: 'USD',
}); /* $2,500.00 */

有关浏览器支持的一些说明

  • 如今,浏览器支持已不再是一个问题,在美国,支持率为 98%,在欧盟为 99%
  • 对于世界其他地区(受支持的用户中有 97%),在支持方面最大的违规者是 Opera Mini,该产品因设计而受到严重损害
  • 有一个垫片 ,以支持它的化石浏览器,你应该真正需要
  • 看看CanIUse了解更多信息

查看 JavaScript Number对象,看看它是否可以帮助您。

  • toLocaleString()将使用位置特定的千位分隔符格式化数字。
  • toFixed()会将数字四舍五入到特定的小数位数。

要同时使用它们,必须将值的类型改回数字,因为它们都输出字符串。

例:

Number((someNumber).toFixed(1)).toLocaleString()

以下是Patrick Desjardins(别名 Daok)代码,其中添加了一些注释和一些小的更改:

/* 
decimal_sep: character used as deciaml separtor, it defaults to '.' when omitted
thousands_sep: char used as thousands separator, it defaults to ',' when omitted
*/
Number.prototype.toMoney = function(decimals, decimal_sep, thousands_sep)
{ 
   var n = this,
   c = isNaN(decimals) ? 2 : Math.abs(decimals), //if decimal is zero we must take it, it means user does not want to show any decimal
   d = decimal_sep || '.', //if no decimal separator is passed we use the dot as default decimal separator (we MUST use a decimal separator)

   /*
   according to [https://stackoverflow.com/questions/411352/how-best-to-determine-if-an-argument-is-not-sent-to-the-javascript-function]
   the fastest way to check for not defined parameter is to use typeof value === 'undefined' 
   rather than doing value === undefined.
   */   
   t = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, //if you don't want to use a thousands separator you can pass empty string as thousands_sep value

   sign = (n < 0) ? '-' : '',

   //extracting the absolute value of the integer part of the number and converting to string
   i = parseInt(n = Math.abs(n).toFixed(c)) + '', 

   j = ((j = i.length) > 3) ? j % 3 : 0; 
   return sign + (j ? i.substr(0, j) + t : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : ''); 
}

这里是一些测试:

//some tests (do not forget parenthesis when using negative numbers and number with no decimals)
alert(123456789.67392.toMoney() + '\n' + 123456789.67392.toMoney(3) + '\n' + 123456789.67392.toMoney(0) + '\n' + (123456).toMoney() + '\n' + (123456).toMoney(0) + '\n' + 89.67392.toMoney() + '\n' + (89).toMoney());

//some tests (do not forget parenthesis when using negative numbers and number with no decimals)
alert((-123456789.67392).toMoney() + '\n' + (-123456789.67392).toMoney(-3));

较小的更改是:

  1. 仅当不是NaN时才将Math.abs(decimals)移到一点。

  2. decimal_sep不能再为空字符串(某种十进制分隔符必须)

  3. 我们使用如何最佳确定是否未将参数发送给 JavaScript 函数中建议的typeof thousands_sep === 'undefined'

  4. 不需要(+n || 0) ,因为this是一个Number对象

JS 小提琴

accounting.js是一个小型的 JavaScript 库,用于数字,货币和货币格式设置。

如果数量是数字,请说-123 ,然后

amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' });

将产生字符串"-$123.00"

这是一个完整的工作示例

这是我见过的最好的 js 货币格式化程序:

Number.prototype.formatMoney = function(decPlaces, thouSeparator, decSeparator) {
    var n = this,
        decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces,
        decSeparator = decSeparator == undefined ? "." : decSeparator,
        thouSeparator = thouSeparator == undefined ? "," : thouSeparator,
        sign = n < 0 ? "-" : "",
        i = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + "",
        j = (j = i.length) > 3 ? j % 3 : 0;
    return sign + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(n - i).toFixed(decPlaces).slice(2) : "");
};

它已重新格式化并从这里借来: https : //stackoverflow.com/a/149099/751484

您必须提供自己的货币标记(您在上面使用了 $)。

像这样调用它(尽管请注意,args 默认为 2,逗号和&,所以如果您愿意的话,您不需要提供任何 args):

var myMoney=3543.75873;
var formattedMoney = '$' + myMoney.formatMoney(2,',','.'); // "$3,543.76"

这里已经有一些不错的答案。这是另一种尝试,只是为了好玩:

function formatDollar(num) {
    var p = num.toFixed(2).split(".");
    return "$" + p[0].split("").reverse().reduce(function(acc, num, i, orig) {
        return  num=="-" ? acc : num + (i && !(i % 3) ? "," : "") + acc;
    }, "") + "." + p[1];
}

和一些测试:

formatDollar(45664544.23423) // "$45,664,544.23"
formatDollar(45) // "$45.00"
formatDollar(123) // "$123.00"
formatDollar(7824) // "$7,824.00"
formatDollar(1) // "$1.00"

编辑:现在它将处理负数

适用于所有当前浏览器

使用toLocaleString以语言敏感的表示形式格式化货币(使用ISO 4217货币代码)。

(2500).toLocaleString("en-GB", {style: "currency", currency: "GBP", minimumFractionDigits: 2})

@avenmore 的南非兰特代码片段示例

console.log((2500).toLocaleString("en-ZA", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> R 2 500,00
console.log((2500).toLocaleString("en-GB", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> ZAR 2,500.00