Как я могу отформатировать числа в виде строки валюты в JavaScript? - PullRequest
1578 голосов
/ 29 сентября 2008

Я бы хотел отформатировать цену в JavaScript.
Я хотел бы функцию, которая принимает float в качестве аргумента и возвращает string в следующем формате:

"$ 2,500.00"

Какой лучший способ сделать это?

Ответы [ 62 ]

1654 голосов
/ 29 сентября 2008

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(n, c, d, t) {
  var c = isNaN(c = Math.abs(c)) ? 2 : c,
    d = d == undefined ? "." : d,
    t = t == undefined ? "," : t,
    s = n < 0 ? "-" : "",
    i = String(parseInt(n = Math.abs(Number(n) || 0).toFixed(c))),
    j = (j = i.length) > 3 ? j % 3 : 0;

  return s + (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) : "");
};

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>
1185 голосов
/ 20 января 2013

Краткое и быстрое решение (работает везде!)

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

Идея, лежащая в основе этого решения, заключается в замене соответствующих разделов первым соответствием и запятой, т.е. '$&,'. Сопоставление выполняется с использованием подхода lookahead . Вы можете прочитать выражение как «соответствует номеру, если за ним следует последовательность из трех наборов чисел (один или несколько) и точка» .

ИСПЫТАНИЯ:

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/

1037 голосов
/ 26 апреля 2013

Intl.numberformat

Javascript имеет средство форматирования чисел (часть API интернационализации).

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

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

JS Fiddle

Используйте undefined вместо первого аргумента ('en-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 */

Некоторые заметки о поддержке браузера

  • Поддержка браузеров в настоящее время больше не является проблемой с поддержкой 97% в США / ЕС
  • Для других частей света (поддерживается 92%) самыми большими нарушителями в плане поддержки являются UC Mobile ( держитесь подальше от этого ) и Opera Mini (покалеченные дизайном)
  • Существует поддержка shim в старых браузерах
  • Посмотрите CanIUse для получения дополнительной информации
197 голосов
/ 29 сентября 2008

Посмотрите на объект JavaScript Number и посмотрите, может ли он вам помочь.

  • toLocaleString() отформатирует число с использованием разделителя тысяч для определенного местоположения.
  • toFixed() округляет число до определенного количества десятичных знаков.

Чтобы использовать их в одно и то же время, необходимо изменить тип значения на число, поскольку они оба выводят строку.

Пример:

Number(someNumber.toFixed(1)).toLocaleString()
159 голосов
/ 19 мая 2010

Ниже приведен код Патрика Дежардинса (псевдоним 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. немного сдвинул Math.abs(decimals), что должно быть сделано только тогда, когда не NaN.

  2. decimal_sep больше не может быть пустой строкой (НЕОБХОДИМО использовать какой-то десятичный разделитель)

  3. мы используем typeof thousands_sep === 'undefined', как предложено в Как наилучшим образом определить, не передается ли аргумент в функцию JavaScript

  4. (+n || 0) не требуется, поскольку this является Number объектом

JS Fiddle

122 голосов
/ 01 сентября 2011

accounting.js - это крошечная библиотека JavaScript для форматирования чисел, денег и валюты.

112 голосов
/ 05 ноября 2014

Если сумма - число, скажем -123, тогда

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

выдаст строку "-$123.00".

Вот полный рабочий пример .

98 голосов
/ 17 февраля 2012

Вот лучший форматер js money, который я видел:

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

Вам нужно будет указать свой собственный обозначение валюты (вы использовали $ выше).

Назовите это так (хотя обратите внимание, что для аргументов по умолчанию установлено значение 2, запятая и точка, поэтому вам не нужно указывать аргументы, если вы предпочитаете это):

var myMoney=3543.75873;
var formattedMoney = '$' + myMoney.formatMoney(2,',','.'); // "$3,543.76"
72 голосов
/ 17 марта 2011

Здесь уже есть несколько отличных ответов. Вот еще одна попытка, просто для удовольствия:

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"

Отредактировано: теперь оно будет обрабатывать и отрицательные числа

69 голосов
/ 17 февраля 2012

Я думаю, что вы хотите f.nettotal.value = "$" + showValue.toFixed(2);

...