Я хочу отформатировать цену в JavaScript. Мне нужна функция, которая принимает float в качестве аргумента и возвращает string в следующем формате:
"$ 2,500.00"
Как лучше всего это сделать?
Пожалуйста, всем, кто будет читать это в будущем, используйте нет для хранения валюты с плавающей запятой. Вы потеряете точность и данные. Вы должны сохранить его как целое число центов (или пенсов и т. д.), А затем преобразовать перед выводом.
@PhilipWhitehouse, что может привести к потере данных с менее чем двумя знаками после запятой?
@ user1308743 Float не хранит десятичные разряды. Он хранит числа, используя значение, базу и смещение. 0,01 на самом деле не представляется. См .: en.wikipedia.org/wiki/Floating_point#Accuracy_problems
@ user1308743: Представьте, что вы представляете очень большое число (допустим, вы счастливчик, и это баланс вашего банковского счета). Вы действительно хотите потерять деньги из-за недостатка точности?
@PhilipWhitehouse прав: хранить деньги как поплавок - определенно плохая идея. Однако хранение денег в виде центов работает только тогда, когда вы имеете дело только с целыми центами, что недостаточно точно для многих операций. Недавно мы перешли на хранение валюты в виде «большого десятичного знака» с 7 знаками после запятой. Вы можете использовать метод Javascript toFixed (7) для имитации этого, хотя при необходимости он возвращает строку. Однако это означает, что вы можете работать со знакомыми форматами $ xx.xx, не конвертируя обратно центов.
Так почему никто не предложил следующее? (2500) .toLocaleString ("en-GB", {style: "currency", currency: "GBP", minimumFractionDigits: 2}) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@NickG Полагаю, из-за того, что поддержка устаревших браузеров довольно дрянная. Но в идеальном мире (где у всех есть современные браузеры) это было бы лучшим решением.
вы можете использовать эту javascript-библиотеку Numeral.js для преобразования ваших чисел в доллары. (numeraljs.com) для справки.
Не забудьте, что в скобках ($#,##0.00) на английском языке указаны отрицательные значения валюты.
@NickG Я был в восторге от вашего решения, но не работает на IPad, Android и IE7, работает только в Mozilla и Opera из того, что я проверял
@TestoTestini - спасибо, кстати, Mozilla задокументировала таблицу совместимости для браузеров developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@TestoTestini (a) NickG См. Этот jsFiddle: jsfiddle.net/v7tws309
@RoccoTheTaco: Не уверен, что вы говорите. Другой вопрос старше, имеет больше голосов, больше ответов и ответ с большим количеством голосов. (Субъективное) среднее качество ответов аналогично. Если честно, их лучше объединить.
Нет ничего плохого в том, чтобы быть универсальным, не так ли?
@PhilipWhitehouse Хотя хранить его как float нехорошо, я считаю, что валюту отображать в js в виде float вполне нормально. Пока вы не выполняете над ним вычисления, например, суммируете столбец и т. д. Я сохраняю и обрабатываю значение в десятичном формате C# и просто отправляю его в js как float, где оно отображается. Если вы наберете в консоли «.1» или «.61», он будет отображаться нормально, хотя «1.03– .42» - нет. Элементарный тест: для (var i = -200; i <= 200; ++ i) console.info (i / 100); Я также отправляю отредактированные числа с плавающей запятой обратно на свой веб-сервер, что должно быть в порядке: JSON.stringify (.1): "0.1".
Если вы читаете это в> = 2017, это должно быть полезно: связь
@ Амир, это уже в мой ответ
@CurtisYallop, только если отображается значение без валюты, потому что english.stackexchange.com/a/11327/118419
@NickGrealy Святое дерьмо. Чувак, я не знал этой функции. Я всегда писал свои кастомные функции. Cooooool. Спасибо
Спасибо, @MikeAron, в любое время. Поставьте +1, чтобы помочь другим - stackoverflow.com/a/18994850/782034
Для конвертации INR используйте (4027775861.4) .toLocaleString ('en-IN', {maximumFractionDigits: 2, style: 'currency', currency: 'INR'}); // возвращает -> "₹ 4,02,77,75,861,40"



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Основная часть - это вставка разделителей тысяч, что можно сделать так:
<script type = "text/javascript">
function ins1000Sep(val){
val = val.split(".");
val[0] = val[0].split("").reverse().join("");
val[0] = val[0].replace(/(\d{3})/g,",");
val[0] = val[0].split("").reverse().join("");
val[0] = val[0].indexOf(",")==0?val[0].substring(1):val[0];
return val.join(".");
}
function rem1000Sep(val){
return val.replace(/,/g,"");
}
function formatNum(val){
val = Math.round(val*100)/100;
val = (""+val).indexOf(".")>-1 ? val + "00" : val + ".00";
var dec = val.indexOf(".");
return dec == val.length-3 || dec == 0 ? val : val.substring(0,dec+3);
}
</script>
<button onclick = "alert(ins1000Sep(formatNum(12313231)));">
Я получаю неправильный вывод числа при вводе отрицательных значений в ins1000Sep ().
Это решение совместимо со всеми основными браузерами:
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, "" + 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,
Если вы можете использовать современный синтаксис 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, "" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
} catch (e) {
console.info(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>Если вы всегда хотите округлить до 5 и меньше 5, вы не можете полагаться на toFixed () из-за стандартных проблем, связанных с представлением чисел с плавающей запятой в двоичном формате. Например, попробуйте (1.005).toFixed(2).
в первую очередь отличный, лаконичный код. однако, если вы американец, вам следует изменить значения по умолчанию для d и t на . и , соответственно, чтобы вам не приходилось указывать их каждый раз. Кроме того, я рекомендую изменить начало инструкции return следующим образом: return s + '$' + [rest], иначе вы не получите знак доллара.
Спасибо, это здорово. Изменен для работы со строками, вводимыми пользователем (сначала преобразует строку в числа, если они вводят 1500 долларов). String.prototype.formatMoney = function (c, d, t) {var n_dirty = this, n = n_dirty.replace (/ [^ \ d.] / G, ''), c = isNaN (c = Math.abs ( в))? 2: c, d = d == undefined? "." : d, t = t == undefined? ",": t, s = n <0? "-": "", i = parseInt (n = Math.abs (+ 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): ""); };
Вы можете использовать «10» в качестве основания в parseInt. В противном случае для любого числа, начинающегося с «0», будет использоваться восьмеричная нумерация.
Значение по умолчанию, равное 0, остается восьмеричным, но не рекомендуется. Но да, вы можете добавить это, если хотите.
Не уверен, почему люди считают этот код красивым. Это не поддается расшифровке. Вроде неплохо работает, но некрасиво.
Копируется ли эта функция formatMoney из какого-нибудь миниатюрного кода JavaScript? А оригинал нельзя выложить? Что обозначают переменные c, d, i, j, n, s и t? Судя по количеству голосов и комментариев к этому сообщению, я могу предположить, что этот код был скопирован и вставлен на производственные веб-сайты повсюду ... Удачи в поддержании кода, если когда-нибудь в нем будет ошибка!
Это решение работает не очень хорошо. 1.155.formatMoney (2, '.', ',) ===' 1.16 ', но 2.155.formatMoney (2,'. ',', ') ===' 2.15 '
"поэзия"? Больше похоже на безвестность. Это не кодовый гольф; используйте небольшое пустое пространство. Правильные имена var тоже не повредят.
Не говоря уже о том, что используется d == undefined, тогда как typeof(d) === 'undefined' должен быть на месте.
@trejder почему так? Если у вас есть глупые программисты, которые определяют undefined как переменную с содержимым, вам хорошо. Кстати, вам не нужно (и поэтому не следует) использовать круглые скобки для typeof.
@MykaEyl Прочтите об основах JS, прежде чем говорить что-то, что ... немного неправильно. Переменная с именем undefined определяется автор: JS, а не некоторыми глупыми программистами, и вы должен используете круглые скобки для typeof, потому что без нее вы будете сравнивать ее с этой переменной с именем undefined. Я не излагаю здесь свои мысли, я просто скопировал то, что выражено во многих ответах SO и во многих источниках. Сейчас нет времени искать пример, но вы обязательно его найдете, если погуглите еще немного.
@trejder Скобки с typeof абсолютно не влияют на то, как конструкция анализирует эту форму - typeof имеет тот же приоритет, что и унарный оператор. Также в предыдущем комментарии говорилось, что это безопасно, чтобы полагаться на то, что undefined оценивается как (void 0), пока «глупый программист» не вводит теневую локальную переменную undefined и не повторно связывает window.undefined. (Я считаю, что нарушителем является этот код, а не код, использующий undefined.)
@ user2864740 Если подумать, я согласен (конечно!) не использовать круглые скобки (я должен был быть слепым, когда впервые читал комментарий Мика Эйл!:]). Но я не согласен со второй частью. Причина, по которой вы должны использовать typeof d === 'undefined' вместо d === undefined, заключается в том, что при первом подходе вам не нужно заботиться о глупые разработчики. Поскольку мир переполнен глупые разработчики, нам нужно тратить время на собственное кодирование, а не на то, чтобы предвидеть возможные попытки глупые разработчики испортить наш код, верно? :]
@trejder Я столкнулся с этой проблемой с никогда. Любая среда, в которой undefined был переопределен на значение, отличное от (void 0), является средой, которую я буду поддерживать нет. (В Python 2.x True и False были просто переменными - например, True,False=False,True допустимо - но никогда не было никаких попыток найти «безопасный» метод.)
@trejder Поскольку мир переполнен глупыми разработчиками, нам нужно тратить время на собственное кодирование, а не на то, чтобы предвидеть возможные попытки глупых разработчиков испортить наш код, верно? => Следуя этой мысли, разве typeof(d) === 'undefined' не является попыткой предвидение возможных попыток глупых разработчиков испортить наш код? Если бы кто-то действительно переопределил undefined, я бы не стал доверять им, чтобы они не сделали что-то еще, чтобы взломать ваш код.
@RobQuist Он почти наверняка имел в виду перевернутый по сравнению с тем, что находится в коде, а не как приглашение к повторной войне за независимость.
Как отмечали предыдущие комментаторы, это не только сбивает с толку, но и неправильно. Это дает 49.65.formatMoney (1, '.', ',') => 49.6
Я использовал это, но получил ошибку, поэтому добавляю var myMoney = Number (myMoney) .toFixed (2); добавление Number () сработало.
В этих комментариях так много ссор. Вау, конечно, код может быть не самым красивым, но если вы заслуживаете внимания как «программист», он определенно не слишком сложный или неразборчивый, если вы умеете читать код. И кто хоть раз поддерживает код, который они скопировали, но не создали сами?
@Deji, к черту стандарты стиля кодирования, именование вещей, структурирование кода, комментирование и аннотирование.
@aross Связан ли этот вопрос со стандартами стиля кодирования, «именованием вещей», структурированием кода, комментированием и аннотацией? Вы неопределенно упоминаете какую-либо из этих концепций, приводя какие-либо причины, по которым приведенный выше конкретный код не является подходящим ответом? Нет...
@Deji Значит, вы даже считаете обфусцированный код хорошим ответом?
@aross Зависит от вопроса. Я думаю, что вы здесь не понимаете - комментарии предназначены не для оценки качества кода, а для оценки качества ОТВЕТА. Мне действительно не нужно объяснять, как обычно оцениваются ответы на вопросы по качеству ...
К счастью, это вики сообщества, так что любой из вас, жалующийся на формат / удобочитаемость кода, может просто исправить это самостоятельно.
Эта функция неверна:> (2030) .formatMoney (0, '.', ''); <"2 03 0"
Странный код, на мой взгляд, напр. value дважды повторно назначается внутри функции, что очень затрудняет отладку. При decimalPlaces = 0 значение неявно округляется на «toFixed», которое в моем случае не имеет отступа.
Как такая ужасная практика получила 1K + голосов? Не говоря уже о том, что он был написан предварительно.
Поскольку мне не нравится код, который я не могу прочитать, я переписал его, чтобы он был удобнее для разработчиков: syntaxwarriors.com/p/18/Format-currency-in-Javascript Практически то же самое, но читабельный.
Неминифицированная версия: josscrowcroft.com/2011/code/… (см. «Формат денег JavaScript»).
Прототип toLocaleString() делает то же самое с меньшим количеством кода. и более надежен. Ответил здесь
Я лично считаю это решение мусором. Вы не используете разумные имена переменных, вы изменяете prototype встроенного модуля с помощью свойства перечислимый, и ваш код даже не имеет смысла, даже если он работает.
Этот ответ сейчас несколько устарел. См. Ответ о формате международного номера ниже.
Код на этом сайте должен быть удобочитаемым для людей, а не для веб-браузеров.
Если дата может быть нулевой, тогда вам нужно вызвать функцию следующим образом: formatMoney(someDate, 2) вместо someDate.formatMoney(2), иначе вы получите «Uncaught TypeError: Cannot read property 'value' of null», когда это так.
Я удивлен, что никто не упомянул, что линия j = (j = i.length) > 3 ? j % 3 : 0; вызывает j до того, как она будет определена.
Этому коду сложно следовать. По крайней мере, дайте несколько имен параметрам.
ПРЕДУПРЕЖДЕНИЕ! Код, отличный от ES6, не работает по состоянию на 31.10.2019, я удивлен, что он получил столько голосов! Исправьте следующие простые случаи: 100000 (результат 100000,00) и 1000000 (результат 1,000000,00)
Код не ES6 не работает, что-то не так с используемым regExpression, я не обновлял свой reg ex годами, поэтому, к сожалению, я не могу его исправить
Очиститель не ES6: функция formatMoney (количество, десятичное число, десятичное число, тысячи) {decimalCount = Math.abs (decimalCount); decimalCount = isNaN (decimalCount)? 2: decimalCount; var negativeSign = количество <0? "-": ""; var i = parseInt (amount = Math.abs (Number (amount) || 0) .toFixed (decimalCount)). toString (); var j = (длина i> 3)? i.length% 3: 0; return negativeSign + (j? i.substr (0, j) +ousands: '') + i.substr (j) .replace (/ (\ d {3}) (? = \ d) / g, "$ 1" + тысяч) + (decimalCount? decimal + Math.abs (количество - i) .toFixed (decimalCount) .slice (2): ""); }
есть ли способ опровергнуть этот ответ. это больше не актуально.
Все просто проголосуют против этого ответа, чтобы правильный ответ был более заметным.
Я хотел бы назвать этот ответ самым популярным ответом, который, ради всего святого, должен быть отвергнут.
Неверный код "Пользовательской функции". Например, при запуске фрагмента кода 1234567.12 возвращается как 1,234567.12, это просто неправильно.
Взгляните на объект JavaScript Число и посмотрите, может ли он вам помочь.
toLocaleString() отформатирует число, используя разделитель тысяч, зависящий от местоположения.toFixed() округляет число до определенного количества десятичных знаков.Чтобы использовать их одновременно, необходимо изменить тип значения на число, потому что оба они выводят строку.
Пример:
Number((someNumber).toFixed(1)).toLocaleString()
Спасибо! На основе этой идеи я смог сделать достаточно короткий и простой! (и с локализацией) Отлично.
На самом деле можно. то есть для долларов: '$' + (значение + 0,001) .toLocaleString (). slice (0, -1)
Похоже, это было бы здорово, но на данный момент поддержка браузеров невелика.
Safari определенно реализует функции toLocale иначе. Форматы даты локали также производят другой вывод, чем любой другой основной браузер.
@acorncom Почему вы говорите, что браузер "почти не поддерживает"? Объект Number существует с Javascript 1.1. Предоставьте ссылку, подтверждающую вашу претензию.
Следует позаботиться о том, чтобы существовала старая версия toLocaleString, использующая системный языковой стандарт, и новая (несовместимая) версия, исходящая от ECMAScript Intl API. Объясняется здесь. Этот ответ, похоже, предназначен для старой версии.
Не уверен, почему за это так проголосовали, но это не соответствует тому, о чем просит OP. Например, 10000 превратится в "10,000", а не в "10,000.00", что является желаемым поведением для форматирования валюты.
По поводу комментария @Burak. Я не думаю, что это так. Для меня код "var currency =" $ "+ Number (someNumber.toFixed (2)). ToLocaleString ()" превращается в var someNumber = 2345667.7899; на $ 2 345 667,79, что мне и нужно.
@Alexander, а что, если someNumber - это «234567» или «234567,8»? Тогда у вас будет ноль или один десятичный знак вместо двух, что не то, чего хочет OP, и, как правило, кажется нежелательным и для форматирования валюты.
Да вы правы. Сейчас я использую прототип Number.prototype.formatMoney, который указан ниже.
лучший ответ на сегодняшний день
Number () является обязательным, если переменная является строкой или любым другим типом. Это мне очень помогло! спасибо, что поделились этим.
Я согласен с @Burak, почему это пока лучший ответ .. кто-нибудь пробовал? он не дает ожидаемого результата
function CurrencyFormatted(amount)
{
var i = parseFloat(amount);
if (isNaN(i)) { i = 0.00; }
var minus = '';
if (i < 0) { minus = '-'; }
i = Math.abs(i);
i = parseInt((i + .005) * 100);
i = i / 100;
s = new String(i);
if (s.indexOf('.') < 0) { s += '.00'; }
if (s.indexOf('.') == (s.length - 2)) { s += '0'; }
s = minus + s;
return s;
}
От WillMaster.
Маленький и простой. Спасибо.
просто, но без запятой для 1000
Кодовая база YUI использует следующее форматирование:
format: function(nData, oConfig) {
oConfig = oConfig || {};
if (!YAHOO.lang.isNumber(nData)) {
nData *= 1;
}
if (YAHOO.lang.isNumber(nData)) {
var sOutput = nData + "";
var sDecimalSeparator = (oConfig.decimalSeparator) ? oConfig.decimalSeparator : ".";
var nDotIndex;
// Manage decimals
if (YAHOO.lang.isNumber(oConfig.decimalPlaces)) {
// Round to the correct decimal place
var nDecimalPlaces = oConfig.decimalPlaces;
var nDecimal = Math.pow(10, nDecimalPlaces);
sOutput = Math.round(nData*nDecimal)/nDecimal + "";
nDotIndex = sOutput.lastIndexOf(".");
if (nDecimalPlaces > 0) {
// Add the decimal separator
if (nDotIndex < 0) {
sOutput += sDecimalSeparator;
nDotIndex = sOutput.length-1;
}
// Replace the "."
else if (sDecimalSeparator !== "."){
sOutput = sOutput.replace(".",sDecimalSeparator);
}
// Add missing zeros
while((sOutput.length - 1 - nDotIndex) < nDecimalPlaces) {
sOutput += "0";
}
}
}
// Add the thousands separator
if (oConfig.thousandsSeparator) {
var sThousandsSeparator = oConfig.thousandsSeparator;
nDotIndex = sOutput.lastIndexOf(sDecimalSeparator);
nDotIndex = (nDotIndex > -1) ? nDotIndex : sOutput.length;
var sNewOutput = sOutput.substring(nDotIndex);
var nCount = -1;
for (var i=nDotIndex; i>0; i--) {
nCount++;
if ((nCount%3 === 0) && (i !== nDotIndex)) {
sNewOutput = sThousandsSeparator + sNewOutput;
}
sNewOutput = sOutput.charAt(i-1) + sNewOutput;
}
sOutput = sNewOutput;
}
// Prepend prefix
sOutput = (oConfig.prefix) ? oConfig.prefix + sOutput : sOutput;
// Append suffix
sOutput = (oConfig.suffix) ? sOutput + oConfig.suffix : sOutput;
return sOutput;
}
// Still not a Number, just return unaltered
else {
return nData;
}
}
это потребует редактирования, поскольку библиотека YUI настраивается, например, вместо oConfig.decimalSeparator на "."
Слишком долго, и мне придется включить YUI
Моя первая реакция была "лол - слишком долго, YUI отстой" ... но после пересмотра, это неплохой код, просто очень ... полный. Он проверяет, действительно ли аргумент является числом (не выполняется другими плакатами, и это единственная часть, которая требует библиотеки YUI). Он округляет (не для всех плакатов). Он имеет настраиваемый разделитель, префикс и суффикс. Наконец, код комментируется и не использует регулярных выражений и сложных однострочных выражений. Итак ... я даю вам +1, чтобы компенсировать другим -1 ... этот код неплох - его можно адаптировать, даже если не использовать YUI.
В YUI они, должно быть, больны, не могут поверить, что написали такой кусок кода.
Хорошо, исходя из того, что вы сказали, я использую это:
var DecimalSeparator = Number("1.2").toLocaleString().substr(1,1);
var AmountWithCommas = Amount.toLocaleString();
var arParts = String(AmountWithCommas).split(DecimalSeparator);
var intPart = arParts[0];
var decPart = (arParts.length > 1 ? arParts[1] : '');
decPart = (decPart + '00').substr(0,2);
return '£ ' + intPart + DecimalSeparator + decPart;
Я открыт для предложений по улучшению (я бы предпочел не включать YUI только для этого :-)) Я уже знаю, что должен обнаружить "." вместо того, чтобы просто использовать его как десятичный разделитель ...
Обратите внимание, что ваша версия неправильно округляет до двух десятичных цифр. Например, 3,706 будет отформатировано как «3,70 фунта стерлингов», а не как «3,71 фунта стерлингов», как должно быть.
Да, в моем конкретном случае это нормально, поскольку суммы, с которыми я работаю, уже имеют не более 2 цифр. Причина, по которой мне нужно исправить до 2 десятичных знаков, - это суммы без десятичных знаков или только с 1.
Минималистичный подход, полностью отвечающий первоначальным требованиям:
function formatMoney(n) {
return "$ " + (Math.round(n * 100) / 100).toLocaleString();
}
@ Даниэль Маглиола: Вы правы, вышесказанное было поспешной и неполной реализацией. Вот исправленная реализация:
function formatMoney(n) {
return "$ " + n.toLocaleString().split(".")[0] + "."
+ n.toFixed(2).split(".")[1];
}
Простите, нет. Это приведет к удалению лишних десятичных знаков, но не к двум десятичным разрядам. «25» будет «25 долларов США» с вашим кодом, а не «25 долларов США».
Все равно ошибаюсь! Вы используете toLocaleString, который может сделать десятичный разделитель "," вместо ".", И предполагается, что это "."
Это был «минималистичный» подход для удовлетворения первоначальных нечетких требований, в которых в качестве примера было указано «2500 долларов США».
Есть javascript-порт функции PHP "number_format".
Я считаю его очень полезным, поскольку он прост в использовании и узнаваем для разработчиков 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 IE 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+'');
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'
Это только одна правильная функция:> number_format (2030, 0, '.', '') <'2 030' Отлично! Спасибо
Ниже приведен код Патрик Дежарден (псевдоним Даок) с небольшими добавленными комментариями и небольшими изменениями:
/*
decimal_sep: character used as decimal separator, 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, "" + 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));
Незначительные изменения:
немного переместил Math.abs(decimals), чтобы делать только тогда, когда это не NaN.
decimal_sep больше не может быть пустой строкой (НЕОБХОДИМО использовать какой-то десятичный разделитель)
мы используем typeof thousands_sep === 'undefined', как предложено в Как лучше всего определить, не отправляется ли аргумент функции JavaScript
(+n || 0) не требуется, поскольку this является объектом Number
Вы можете использовать «10» в качестве основания в parseInt. В противном случае для любого числа, начинающегося с «0», будет использоваться восьмеричная нумерация.
@ sohtimsso1970: извините за поздний ответ, но не могли бы вы объяснить еще кое-что? Я не понимаю, где число может интерпретироваться как восьмеричное. parseInt вызывается по абсолютному значению целой части числа. Часть INTEGER не может начинаться с ZERO, если только это не просто ZERO! А parseInt(0) === 0 либо восьмеричный, либо десятичный.
попробуйте, например: parseInt ("016") ... возвращает 14, поскольку parseInt предполагает, что он закодирован в восьмеричной системе, когда строка начинается с нуля.
@ Tracker1: Я понял, что число, начинающееся с 0, parseInt считает восьмеричным. Но в этом коде НЕВОЗМОЖНО для parseInt получить 016 в качестве ввода (или любое другое восьмеричное форматированное значение), потому что аргумент, переданный parseInt, первым обрабатывается функцией Math.abs. Таким образом, parseInt не сможет получить число, начинающееся с нуля, если только это не просто ноль или 0.nn (где nn - десятичные числа). Но строки 0 и 0.nn будут преобразованы parseInt в простой ZERO, как и предполагалось.
Эта функция неверна:> (2030) .toMoney (0, '.', ''); <"2 03 0"
@AntonPRobul это неправда, вы можете проверить это с помощью ссылки JS FIddle, добавленной в ответ, (2030).toMoney(0, '.', ' '); дает следующее: "2 030", что является ожидаемым результатом, поскольку вы указываете функции использовать один пробел в качестве разделителя тысяч.
function getMoney(A){
var a = new Number(A);
var b = a.toFixed(2); //get 12345678.90
a = parseInt(a); // get 12345678
b = (b-a).toPrecision(2); //get 0.90
b = parseFloat(b).toFixed(2); //in case we get 0.0, we pad it out to 0.00
a = a.toLocaleString();//put in commas - IE also puts in .00, so we'll get 12,345,678.00
//if IE (our number ends in .00)
if (a < 1 && a.lastIndexOf('.00') == (a.length - 3))
{
a=a.substr(0, a.length-3); //delete the .00
}
return a+b.substr(1);//remove the 0 from b, then return a + b = 12,345,678.90
}
alert(getMoney(12345678.9));
Это работает в FF и IE
Как обычно, есть несколько способов сделать одно и то же, но я бы не стал использовать Number.prototype.toLocaleString, поскольку он может возвращать разные значения в зависимости от пользовательских настроек.
Я также не рекомендую расширять Number.prototype - расширение прототипов собственных объектов - плохая практика, поскольку это может вызвать конфликты с кодом других людей (например, библиотеки / фреймворки / плагины) и может быть несовместимо с будущими реализациями / версиями JavaScript.
Я считаю, что регулярные выражения - лучший подход к решению проблемы, вот моя реализация:
/**
* Converts number into currency format
* @param {number} number Number that should be converted.
* @param {string} [decimalSeparator] Decimal separator, defaults to '.'.
* @param {string} [thousandsSeparator] Thousands separator, defaults to ','.
* @param {int} [nDecimalDigits] Number of decimal digits, defaults to `2`.
* @return {string} Formatted string (e.g. numberToCurrency(12345.67) returns '12,345.67')
*/
function numberToCurrency(number, decimalSeparator, thousandsSeparator, nDecimalDigits){
//default values
decimalSeparator = decimalSeparator || '.';
thousandsSeparator = thousandsSeparator || ',';
nDecimalDigits = nDecimalDigits == null? 2 : nDecimalDigits;
var fixed = number.toFixed(nDecimalDigits), //limit/add decimal digits
parts = new RegExp('^(-?\d{1,3})((?:\d{3})+)(\.(\d{'+ nDecimalDigits +'}))?$').exec( fixed ); //separate begin [], middle [] and decimal digits []
if (parts){ //number >= 1000 || number <= -1000
return parts[1] + parts[2].replace(/\d{3}/g, thousandsSeparator + '$&') + (parts[4] ? decimalSeparator + parts[4] : '');
}else{
return fixed.replace('.', decimalSeparator);
}
}
отредактировано 30.08.2010: добавлена возможность установки количества десятичных цифр.отредактировано 2011/08/23: добавлена возможность установить количество десятичных цифр равным нулю.
Смысл toLocaleString в том, что он настраивается в соответствии с настройками пользователя.
Здесь уже есть отличные ответы. Вот еще одна попытка, просто для удовольствия:
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) // ",664,544.23"
formatDollar(45) // ".00"
formatDollar(123) // "3.00"
formatDollar(7824) // ",824.00"
formatDollar(1) // ".00"
Отредактировано: теперь он также будет обрабатывать отрицательные числа
поэзия. блестящий. Вы пробовали reduceRight () developer.mozilla.org/en/JavaScript/Reference/Global_Objects /…, который должен устранить reverse ()?
@Steve - Вы правы, но вам нужно сделать что-то вроде i = orig.length - i - 1 в обратном вызове. Тем не менее, на один обход массива меньше.
Не о совместимости: метод reduce был представлен в Ecmascript 1.8 и не поддерживается в Internet Explorer 8 и ниже.
Как сказал @Blaise, этот метод не будет работать в IE 8 или ниже.
Да, конечно, правильно. Как отмечено в самом ответе, это просто для развлечения. Кроме того, он должен нормально обрабатывать отрицательные числа.
Отрицательные числа у меня работали нормально. Что мне нравится в этом, так это то, что кода не так много, и он не зависит от регулярного выражения.
Почему вы просто не сделали (parseInt(p[0])).toLocaleString()?
Потому что эта функция может давать разные результаты в разных регионах. Это вполне может быть то, что вы хотите, но это не дает прямого ответа на конкретный вопрос о форматировании. (Также обратите внимание на дату в вопросе / ответах здесь.)
чтобы правильно обрабатывать отрицательное число, добавьте следующий код перед возвратом num= = "-" ? acc: <br> т.е. функция, переданная в метод уменьшения, будет иметь вид <br> function(acc, num, i, orig) { return num= = "-" ? acc:num + (i && !(i % 3) ? "," : "") + acc; }
Но как это сделать в валюте евро?
Пример Патрика Дежардена (бывшего Даока) хорошо мне подошел. Я перенес на coffeescript, если кому интересно.
Number.prototype.toMoney = (decimals = 2, decimal_separator = ".", thousands_separator = ",") ->
n = this
c = if isNaN(decimals) then 2 else Math.abs decimals
sign = if n < 0 then "-" else ""
i = parseInt(n = Math.abs(n).toFixed(c)) + ''
j = if (j = i.length) > 3 then j % 3 else 0
x = if j then i.substr(0, j) + thousands_separator else ''
y = i.substr(j).replace(/(\d{3})(?=\d)/g, "" + thousands_separator)
z = if c then decimal_separator + Math.abs(n - i).toFixed(c).slice(2) else ''
sign + x + y + z
Это может сработать:
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));
}
Никаких циклов, никаких регулярных выражений, никаких массивов, никаких экзотических условных выражений.
javascript-number-formatter (ранее в Код Google)
#,##0.00 или с отрицанием -000.####.# ##0,00, #,###.##, #'###.##, или любой тип символа без нумерации.#,##,#0.000 или #,###0.## действительны.##,###,##.# или 0#,#00#.###0# все в порядке.format( "0.0000", 3.141592).(отрывок из README)
вот быстрый способ использования regexp и replace.
function formatCurrency( number, dp, ts ) {
var num = parseFloat( number ); //convert to float
var pw; //for IE
dp = parseInt( dp, 10 ); //decimal point
dp = isNaN( dp ) ? 2 : dp; //default 2 decimal point
ts = ts || ','; //thousands separator
return num != number ?
false : //return false for NaN
( ( 0.9 ).toFixed( 0 ) == '1' ? //for cater IE toFixed bug
num.toFixed( dp ) : //format to fix n decimal point with round up
( Math.round( num * ( pw = Math.pow( 10, dp ) || 1 ) ) / pw ).toFixed( dp ) //for fix ie toFixed bug on round up value like 0.9 in toFixed
).replace( /^(-?\d{1,3})((\d{3})*)(\.\d+)?$/, function( all, first, subsequence, dmp, dec ) { //separate string into different parts
return ( first || '' ) + subsequence.replace( /(\d{3})/g, ts + '' ) + ( dec || '' ); //add thousands seperator and re-join all parts
} );
}
приведите пример использования этой функции.
Использую библиотеку Глобализировать (от Microsoft):
Это отличный проект для локализации чисел, валют и дат, а также для их автоматического форматирования в соответствии с локалью пользователя! ... и, несмотря на то, что это должно быть расширение jQuery, в настоящее время это 100% независимая библиотека. Предлагаю всем попробовать! :)
Вау, почему за это не проголосовали больше? Большая стандартизированная библиотека для всевозможного форматирования. Стандартные для отрасли параметры форматирования с правильной глобализацией. Отличный ответ !!
Это все еще считается альфа-стадией, поэтому используйте осторожно, но отличная находка.
Больше не в альфа (или бета). Это кажется очень полезным, пока мы ждем, пока Safari не будет соответствовать новому стандарту, а IE <11 умрет.
бухгалтерский учет.js - это крошечная библиотека JavaScript для форматирования чисел, денег и валюты.
... просто не забудьте передать символ валюты, иначе он выйдет из строя в IE7 и IE8, IE9 в любом случае в порядке
Похоже, ошибка IE7 / IE8 исправлена.
Это отличная библиотека, возможность передавать символ валюты также является хорошей идеей, поскольку все детали валюты содержатся в одном вызове / настройках функции.
Мне нравится то, что вы можете сделать обратное - передать отформатированную строку валюты и получить числовое значение.
Продолжайте голосовать за это, так как это лучшее решение (если не лучший ответ).
account.js, похоже, не поддерживается в последнее время. Один форк с недавними изменениями - github.com/nashdot/accounting-js
Более быстрый способ с регулярным выражением?
Number.prototype.toMonetaryString=function(){var n=this.toFixed(2),m;
// var=this.toFixed(2).replace(/\./,','); for comma separator
// with a space for thousands separator
while ((m=n.replace(/(\d)(\d\d\d)\b/g,' '))!=n) n=m;
return m;
}
String.prototype.fromMonetaryToNumber=function(s){
return this.replace(/[^\d-]+/g,'')/100;
}
Простой вариант для правильного размещения запятой, сначала поменяв местами строку и базовое регулярное выражение.
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, ',' ).reverse();
};
Более короткий метод (для вставки пробела, запятой или точки) с регулярным выражением?
Number.prototype.toCurrencyString=function(){
return this.toFixed(2).replace(/(\d)(?=(\d{3})+\b)/g,' ');
}
n=12345678.9;
alert(n.toCurrencyString());
Это потрясающе! Должны быть лучшие ответы!
В JavaScript нет эквивалента formatNumber. Вы можете написать это сами или найти библиотеку, которая уже это делает.
Я думаю, что вам нужен f.nettotal.value = "$" + showValue.toFixed(2);
@ crush это работает, но больше не переносит расчеты в налоговое поле?
После того, как вы добавите к нему знак $, это уже не число, а строка.
Эта опция не ставит запятую между тысячами. :-(
Вот лучший форматировщик денег JavaScript, который я видел:
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, "" + 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,',','.'); // ",543.76"
следите за глобальным знаком, i, j
@hacklikecrack, все переменные локальные; они указаны в заявлении var.
извините, да, хотя вы пересказываете аргументы. Отступ! ;)
Ужасное использование имен переменных!
В function есть встроенный javascripttoFixed
var num = new Number(349);
document.write("$" + num.toFixed(2));
Этот ответ выглядит излишним. Ответ Crush уже упоминался toFixed()
toFixed() является функцией объекта Number и не будет работать на var num, если это был String, поэтому мне помог дополнительный контекст.
Патрик Дежарден 'ответ выглядит хорошо, но я предпочитаю простой javascript. Вот функция, которую я только что написал, чтобы взять число и вернуть его в денежном формате (без знака доллара)
// Format numbers to two decimals with commas
function formatDollar(num) {
var p = num.toFixed(2).split(".");
var chars = p[0].split("").reverse();
var newstr = '';
var count = 0;
for (x in chars) {
count++;
if (count%3 == 1 && count != 1) {
newstr = chars[x] + ',' + newstr;
} else {
newstr = chars[x] + newstr;
}
}
return newstr + "." + p[1];
}
Мне нужно, чтобы что-то работало как в браузере, так и в старой версии Node. Это сработало отлично. Спасибо
String.prototype.toPrice = function () {
var v;
if (/^\d+(,\d+)$/.test(this))
v = this.replace(/,/, '.');
else if (/^\d+((,\d{3})*(\.\d+)?)?$/.test(this))
v = this.replace(/,/g, "");
else if (/^\d+((.\d{3})*(,\d+)?)?$/.test(this))
v = this.replace(/\./g, "").replace(/,/, ".");
var x = parseFloat(v).toFixed(2).toString().split("."),
x1 = x[0],
x2 = ((x.length == 2) ? "." + x[1] : ".00"),
exp = /^([0-9]+)(\d{3})/;
while (exp.test(x1))
x1 = x1.replace(exp, "" + "," + "");
return x1 + x2;
}
alert("123123".toPrice()); //123,123.00
alert("123123,316".toPrice()); //123,123.32
alert("12,312,313.33213".toPrice()); //12,312,313.33
alert("123.312.321,32132".toPrice()); //123,312,321.32
+1 Джонатану М. за предоставленный оригинальный метод. Поскольку это явно средство форматирования валюты, я пошел дальше и добавил к выходным данным символ валюты (по умолчанию «$») и добавил запятую по умолчанию в качестве разделителя тысяч. Если вам на самом деле не нужен символ валюты (или разделитель тысяч), просто используйте "" (пустую строку) в качестве аргумента для него.
Number.prototype.formatMoney = function(decPlaces, thouSeparator, decSeparator, currencySymbol) {
// check the args and supply defaults:
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
decSeparator = decSeparator == undefined ? "." : decSeparator;
thouSeparator = thouSeparator == undefined ? "," : thouSeparator;
currencySymbol = currencySymbol == undefined ? "$" : currencySymbol;
var n = this,
sign = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(decPlaces)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return sign + currencySymbol + (j ? i.substr(0, j) + thouSeparator : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "" + thouSeparator) + (decPlaces ? decSeparator + Math.abs(n - i).toFixed(decPlaces).slice(2) : "");
};
Первая переменная выглядит довольно странно, поскольку эти переменные уже объявлены в объявлении функции. Кроме этого, спасибо!
Ты прав. Это ошибка, которую я перенес из оригинала Джонатана М., где все они связаны как одно выражение var. Это должны быть простые задания. Исправление.
В этом отношении, я думаю, что это, вероятно, преждевременно оптимизировано и должно быть переработано для удобства чтения. Но моей целью было дополнить код OP, а не принципиально его изменить.
Это не так уж и плохо - +n || 0 - единственное, что кажется немного странным (по крайней мере, мне).
this - очень полезное имя переменной. Преобразование его в n, чтобы вы могли сохранить 3 символа во время определения, возможно, было необходимо в эпоху, когда ОЗУ и пропускная способность считались в КБ, но это просто запутывание в эпоху, когда минификатор позаботится обо всем этом, прежде чем он когда-либо попадет в производство. . Остальные умные микрооптимизации по крайней мере спорны.
Верно - не поймал.
если кто-то хочет отменить formatMoney обратно, вот код: String.prototype.undoFormatMoney = function () {var tempVals; var val = this; var sign = ((val.split ('$') [0]) == "-")? "-": "", val = val.split ('$') [1]; tempVals = val.split (','); val = 0; var adjPlaces = 1; len1 = (tempVals.length) - 1; for (var i = len1, j = 0; i> = 0; i--, j ++) {если (j> 0) {adjPlaces = j * 1000; } val = val + ((tempVals [i]) * adjPlaces); } знак возврата + "" + val; };
Coffeescript для популярного ответа Патрика выше:
Number::formatMoney = (decimalPlaces, decimalChar, thousandsChar) ->
n = this
c = decimalPlaces
d = decimalChar
t = thousandsChar
c = (if isNaN(c = Math.abs(c)) then 2 else c)
d = (if d is undefined then "." else d)
t = (if t is undefined then "," else t)
s = (if n < 0 then "-" else "")
i = parseInt(n = Math.abs(+n or 0).toFixed(c)) + ""
j = (if (j = i.length) > 3 then j % 3 else 0)
s + (if j then i.substr(0, j) + t else "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "" + t) + (if c then d + Math.abs(n - i).toFixed(c).slice(2) else "")
Numeral.js - js-библиотека для удобного форматирования чисел с помощью @adamwdraper
numeral(23456.789).format('$0,0.00'); // = "$23,456.79"
Форк Numbro, кажется, получает больше любви, поскольку Numeral.js кажется заброшенным: github.com/foretagsplatsen/numbro
Numeral.js снова активен.
Я предлагаю класс NumberFormat из API визуализации Google.
Вы можете сделать что-то вроде этого:
var formatter = new google.visualization.NumberFormat({
prefix: '$',
pattern: '#,###,###.##'
});
formatter.formatValue(1000000); // $ 1,000,000
Я надеюсь, что это помогает.
Вот мой ...
function thousandCommas(num) {
num = num.toString().split('.');
var ints = num[0].split('').reverse();
for (var out=[],len=ints.length,i=0; i < len; i++) {
if (i > 0 && (i % 3) === 0) out.push(',');
out.push(ints[i]);
}
out = out.reverse() && out.join('');
if (num.length === 2) out += '.' + num[1];
return out;
}
http://code.google.com/p/javascript-number-formatter/:
ОБНОВИТЬ Это моя домашняя утилита pp для наиболее распространенных задач:
var NumUtil = {};
/**
Petty print 'num' wth exactly 'signif' digits.
pp(123.45, 2) == "120"
pp(0.012343, 3) == "0.0123"
pp(1.2, 3) == "1.20"
*/
NumUtil.pp = function(num, signif) {
if (typeof(num) !== "number")
throw 'NumUtil.pp: num is not a number!';
if (isNaN(num))
throw 'NumUtil.pp: num is NaN!';
if (num < 1e-15 || num > 1e15)
return num;
var r = Math.log(num)/Math.LN10;
var dot = Math.floor(r) - (signif-1);
r = r - Math.floor(r) + (signif-1);
r = Math.round(Math.exp(r * Math.LN10)).toString();
if (dot >= 0) {
for (; dot > 0; dot -= 1)
r += "0";
return r;
} else if (-dot >= r.length) {
var p = "0.";
for (; -dot > r.length; dot += 1) {
p += "0";
}
return p+r;
} else {
return r.substring(0, r.length + dot) + "." + r.substring(r.length + dot);
}
}
/** Append leading zeros up to 2 digits. */
NumUtil.align2 = function(v) {
if (v < 10)
return "0"+v;
return ""+v;
}
/** Append leading zeros up to 3 digits. */
NumUtil.align3 = function(v) {
if (v < 10)
return "00"+v;
else if (v < 100)
return "0"+v;
return ""+v;
}
NumUtil.integer = {};
/** Round to integer and group by 3 digits. */
NumUtil.integer.pp = function(num) {
if (typeof(num) !== "number") {
console.info("%s", new Error().stack);
throw 'NumUtil.integer.pp: num is not a number!';
}
if (isNaN(num))
throw 'NumUtil.integer.pp: num is NaN!';
if (num > 1e15)
return num;
if (num < 0)
throw 'Negative num!';
num = Math.round(num);
var group = num % 1000;
var integ = Math.floor(num / 1000);
if (integ === 0) {
return group;
}
num = NumUtil.align3(group);
while (true) {
group = integ % 1000;
integ = Math.floor(integ / 1000);
if (integ === 0)
return group + " " + num;
num = NumUtil.align3(group) + " " + num;
}
return num;
}
NumUtil.currency = {};
/** Round to coins and group by 3 digits. */
NumUtil.currency.pp = function(amount) {
if (typeof(amount) !== "number")
throw 'NumUtil.currency.pp: amount is not a number!';
if (isNaN(amount))
throw 'NumUtil.currency.pp: amount is NaN!';
if (amount > 1e15)
return amount;
if (amount < 0)
throw 'Negative amount!';
if (amount < 1e-2)
return 0;
var v = Math.round(amount*100);
var integ = Math.floor(v / 100);
var frac = NumUtil.align2(v % 100);
var group = integ % 1000;
integ = Math.floor(integ / 1000);
if (integ === 0) {
return group + "." + frac;
}
amount = NumUtil.align3(group);
while (true) {
group = integ % 1000;
integ = Math.floor(integ / 1000);
if (integ === 0)
return group + " " + amount + "." + frac;
amount = NumUtil.align3(group) + " " + amount;
}
return amount;
}
это просто скопировано из поиска Google. Проект не обновлялся с 2011 года.
(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/
На самом деле я пошел еще дальше: .replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, ",").
Версия CoffeeScript с регулярным выражением VisioN и kalisjoshua и способом указания десятичного разряда (так что вы можете оставить значение по умолчанию 2 или указать 0 без десятичного числа): Number.prototype.toMoney = (decimal=2) -> @toFixed(decimal).replace /(\d)(?=(\d{3})+(?:\.\d+)?$)/g, ","
Если мы вызовем toFixed (0), запятые исчезнут, есть идеи, как заставить его работать с this.toFixed(0).replace(/(\d)(?=(\d{3})+\.)/g, ",")?
@Abbas Да, замените \. на $ (конец строки), то есть this.toFixed(0).replace(/(\d)(?=(\d{3})+$)/g, ",").
Привет, @VisioN, не могли бы вы объяснить регулярное выражение и важность «$ 1». Я использовал функцию регулярного выражения, но пропустил $ в «$ 1». Значит, результат оказался неверным. Помогу мне, если сможешь объяснить. TIA.
@hanumant Обычная грамматика здесь немного сложна, поэтому я предлагаю вам сначала прочитать руководства по регулярным выражениям (например, на MDN). Идея заключается в замене совпавших разделов первым совпадением и запятой, то есть ,. Сопоставление выполняется с помощью опережающий подход. Вы можете прочитать это выражение как "сопоставить число, если за ним следует последовательность из трех наборов чисел (один или несколько) и точка".
@VisioN в случае значений по бразильским стандартам (1,222,333,44 реалов), получающих (122233344). Как это сделать? Я безуспешно пробовал некоторые изменения в скрипке. Не могли бы вы мне помочь? (или даже добавьте формат 3 в свой пример, если особо не о чем просить). Я знаю, что принятый ответ покрывает это, но и ваш тоже отлично
@Michel Вот супер-расширенная версия, которая поддерживает разные типы разделителей: jsfiddle.net/hAfMM/610.
@VisioN: Ваше короткое решение не работает для длинных номеров. Необходимо заменить \. на a \ b (от слова boudarie), как я предложил 4 января 2012 года (см. ниже).
@ JuliendePrabère Приведите пример длинного числа, которое не работает при таком подходе.
@ Gyrocode.com Почему подход $& вам не подошел?
Дополнительная супер расширенная версия: jsfiddle.net/hAfMM/2269 Интегрирует символ валюты
Почему это не лучший ответ? Он рассмотрел все возможные варианты
хорошо, классный код, к сожалению, я многое не понимаю, но это было очень полезно, спасибо
@ 1111161171159459134 Это всего лишь короткая и быстрая альтернатива Math.floor(n). Если вы хотите сделать его совместимым с JSHint, замените этот бит соответствующим образом.
Отличный код. Можно ли сделать обратное, например неформатирование (от 12.345.678,90 до 12345678.9), аналогично любому денежному формату с обычным числом @VisioN
@MohammedFarooq Конечно, так просто: jsfiddle.net/hAfMM/3934.
@ VisioN - Спасибо, но мне не нужно передавать (запятую и точку) в качестве параметра. Мне нужно вернуть число, если я прохожу (от 12,345,678,90 до 12345678,9) или (от 12,345,678,90 до 12345678,9). E В другом евро или стандартном формате на обычное число
@MohammedFarooq Чтобы это работало, скрипт должен знать, в каком стиле отформатирован ваш номер. Он не может автоматически определять, используется ли точка или запятая в качестве разделителя для разделов или десятичной части. В противном случае вам придется использовать строгий числовой формат, чтобы синтаксический анализатор мог угадать, какой символ от какой части разделяет.
Как мне отформатировать номер 12514652? Я не могу называть 12514652.format() рубином ... так?
Спасибо за Ваш ответ. Но у меня есть вопрос: как убрать e + из числа? например, 1000000000000000000000 теперь форматируется как: $ 1e + 21, но я бы хотел, чтобы это было так: $ 1,000,000,000,000,000,000,000.00
@Besat Это сложный вопрос, но мы можем использовать хороший обходной путь с помощью специального метода Number.prototype.toFixed, который может неявно преобразовывать числа в экспоненциальной нотации в их полноразмерное строковое представление. См. Решение здесь: jsfiddle.net/hAfMM/4027.
Чудесно! Спасибо!
как сделать пример arr [i] .price, отформатированный под это? этот код отлично работает! @Зрение
@aross К сожалению, Intl API по-прежнему недоступно во многих широко используемых браузерах, и это решение будет иметь смысл, когда требования совместимости включают IE9, IE10, Safari 9 и т. д.
@aross Часто включение 2-3 строк кода быстрее и проще, чем встраивание библиотеки объемом 50+ КБ, чтобы получить тот же результат. Это зависит от того, что вы на самом деле делаете. Я до сих пор использую этот код в своих проектах, когда мне просто нужно отформатировать число в простом формате.
@aross Мой опыт говорит об обратном: этого кода хватает в 90% случаев. Я не знаю, что такое группировка индейских цифр, но уверен, что это решение можно легко настроить под нее. Поймите меня правильно, я не говорю, что этот ответ является лучшим на сегодняшний день в 2017 году, но я вполне уверен, что разработчики все равно найдут его полезным.
VisioN, вы правы - я выбираю первое из ваших коротких решений, которое, кстати, является великолепным регулярным выражением! Спасибо, что поделились, у меня появился нейрон.
Моя версия TS, которая работает во многих случаях: export const formatNumberToUSFormat = (numberToFormat: number | string) => { const stringNumber = numberToFormat.toString() return stringNumber.match(/\./g) ? stringNumber.replace(/\d(?=(\d{3})+\.)/g, '$&,') : stringNumber.replace(/\d(?=(\d{3})+$)/g, '$&,') }
Это отличное решение! но я пробовал использовать его для числа, начинающегося с 0, например, (012345).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'). Он возвращает «5 349,00» вместо «12 345,00»
@ olaoluwa_98 Числа, начинающиеся с нуля, считаются восьмеричными литералами, поэтому 012345 - это 5349 в десятичной системе счисления. Вам не разрешено использовать восьмеричные литералы в строгом режиме.
Мои 2 цента: для неимперских (истов) парней
Как это сделать с событием на входе при наборе текста?
Эти встроенные функции форматирования несовместимы (требуются данные локали ...), поэтому это регулярное выражение - спаситель.
Вот реализация mootools 1.2 из кода, предоставленного XMLilley ...
Number.implement('format', function(decPlaces, thouSeparator, decSeparator){
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
decSeparator = decSeparator === undefined ? '.' : decSeparator;
thouSeparator = thouSeparator === undefined ? ',' : thouSeparator;
var num = this,
sign = num < 0 ? '-' : '',
i = parseInt(num = Math.abs(+num || 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, '' + thouSeparator) + (decPlaces ? decSeparator + Math.abs(num - i).toFixed(decPlaces).slice(2) : '');
});
Это может быть немного поздно, но вот метод, который я только что разработал для коллеги, чтобы добавить функцию .toCurrencyString() с учетом локали ко всем числам. Интернализация предназначена только для группировки номеров, а НЕ для знака валюты - если вы выводите доллары, используйте "$" в том виде, в котором он поставляется, потому что 3 4567 в Японии или Китае - это то же количество долларов США, что и ,234,567 здесь, в США. Если вы выводите евро и т. д., Измените знак валюты с "$".
Объявите это в любом месте вашего HEAD или там, где это необходимо, непосредственно перед тем, как вам понадобится его использовать:
Number.prototype.toCurrencyString = function(prefix, suffix) {
if (typeof prefix === 'undefined') { prefix = '$'; }
if (typeof suffix === 'undefined') { suffix = ''; }
var _localeBug = new RegExp((1).toLocaleString().replace(/^1/, '').replace(/\./, '\.') + "$");
return prefix + (~~this).toLocaleString().replace(_localeBug, '') + (this % 1).toFixed(2).toLocaleString().replace(/^[+-]?0+/,'') + suffix;
}
Тогда все готово! Используйте (number).toCurrencyString() везде, где вам нужно вывести число в виде валюты.
var MyNumber = 123456789.125;
alert(MyNumber.toCurrencyString()); // alerts "3,456,789.13"
MyNumber = -123.567;
alert(MyNumber.toCurrencyString()); // alerts "$-123.57"
Потому что почему бы не добавить еще один ответ. Я во многом основывал это на ответе VisioN.
function format (val) {
val = (+val).toLocaleString();
val = (+val).toFixed(2);
val += "";
return val.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "" + 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.info(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
Просто для развлечения.
В JavaScript есть средство форматирования чисел (часть API интернационализации).
// Create our number formatter.
var formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
// These options are needed to round to whole numbers if that's what you want.
//minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as ,500.1)
//maximumFractionDigits: 0, // (causes 2500.99 to be printed as ,501)
});
formatter.format(2500); /* ,500.00 */
Используйте undefined вместо первого аргумента ('en-US' в примере), чтобы использовать языковой стандарт системы (языковой стандарт пользователя в случае, если код выполняется в браузере). Дальнейшее объяснение кода локали.
Вот список кодов валют.
Последнее замечание по сравнению со старым .toLocaleString. Оба они предлагают практически одинаковые функции. Однако toLocaleString в своих более старых воплощениях (pre-Intl) на самом деле не поддерживает локали: он использует системную локаль. Поэтому при отладке старых браузеров убедитесь, что вы используете правильную версию (MDN предлагает проверить наличие Intl). Не нужно об этом вообще беспокоиться, если вам не нужны старые браузеры или вы просто используете прокладка.
Кроме того, производительность обоих одинакова для элемента не замужем, но если вам нужно отформатировать много чисел, использование Intl.NumberFormat будет примерно в 70 раз быстрее. Поэтому обычно лучше использовать Intl.NumberFormat и создавать только один экземпляр на каждую загрузку страницы. Во всяком случае, вот эквивалентное использование toLocaleString:
(2500).toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
}); /* ,500.00 */
Голосую за это, потому что это глупо простой ответ, который работает изначально.
Совершенно уверен, что довольно большое количество браузеров теперь поддерживают это. За это следует проголосовать гораздо больше.
Это отличный ответ, и у меня он работает с динамической стоимостью валюты, поэтому, если используется в Европе, она меняется на евро и показывает знак евро. Работает удовольствие!
Отлично работает и в React Native!
Сейчас 2018 год, и это в основном поддерживается повсюду. Это должен быть правильный ответ.
Поддерживается еще в Internet Explorer 11 (IE 11), а также поддерживаются все основные браузеры.
есть ли способ отменить это, вернув 2500,00 долларов в строку, например 2500,00
@RkuangDev Конечно, но вам нужно знать используемый десятичный разделитель. Если это точка (самый простой сценарий), это будет работать: parseFloat(',345.67'.replace(/[^0-9.]/g, '')). Разумеется, остерегайтесь плавающих валютных курсов.
Почему это не принятый ответ? Красиво работает!
Этот ответ соответствует следующим критериям:
Этот код основан на концепциях из других ответов. Его скорость выполнения должна быть среди лучших, если это вызывает беспокойство.
var decimalCharacter = Number("1.1").toLocaleString().substr(1,1);
var defaultCurrencyMarker = "$";
function formatCurrency(number, currencyMarker) {
if (typeof number != "number")
number = parseFloat(number, 10);
// if NaN is passed in or comes from the parseFloat, set it to 0.
if (isNaN(number))
number = 0;
var sign = number < 0 ? "-" : "";
number = Math.abs(number); // so our signage goes before the $ symbol.
var integral = Math.floor(number);
var formattedIntegral = integral.toLocaleString();
// IE returns "##.00" while others return "##"
formattedIntegral = formattedIntegral.split(decimalCharacter)[0];
var decimal = Math.round((number - integral) * 100);
return sign + (currencyMarker || defaultCurrencyMarker) +
formattedIntegral +
decimalCharacter +
decimal.toString() + (decimal < 10 ? "0" : "");
}
Эти тесты работают только на компьютере с локализацией в США. Это решение было принято для простоты и потому, что это могло вызвать плохой ввод (плохая автоматическая локализация) и проблемы с выводом.
var tests = [
// [ input, expected result ]
[123123, "3,123.00"], // no decimal
[123123.123, "3,123.12"], // decimal rounded down
[123123.126, "3,123.13"], // decimal rounded up
[123123.4, "3,123.40"], // single decimal
["123123", "3,123.00"], // repeat subset of the above using string input.
["123123.123", "3,123.12"],
["123123.126", "3,123.13"],
[-123, "-3.00"] // negatives
];
for (var testIndex=0; testIndex < tests.length; testIndex++) {
var test = tests[testIndex];
var formatted = formatCurrency(test[0]);
if (formatted == test[1]) {
console.info("Test passed, \"" + test[0] + "\" resulted in \"" + formatted + "\"");
} else {
console.error("Test failed. Expected \"" + test[1] + "\", got \"" + formatted + "\"");
}
}
Работает со всеми текущими браузерами
Используйте toLocaleString для форматирования валюты в ее языковом представлении (используя коды валют ISO 4217).
(2500).toLocaleString("en-GB", {style: "currency", currency: "GBP", minimumFractionDigits: 2})
Примеры фрагментов кода южноафриканского рэнда для @avenmore
console.info((2500).toLocaleString("en-ZA", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> R 2 500,00
console.info((2500).toLocaleString("en-GB", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}))
// -> ZAR 2,500.00Поскольку аргументы «locales» и «options» поддерживаются очень небольшим количеством браузеров, например Chrome 24, IE11 и Opera 15. Firefox, Safari и другие более старые версии по-прежнему не поддерживают его.
Согласен, он не полностью поддерживается во всех браузерах (пока), но все же является решением. (И, возможно, наиболее верное решение, поскольку оно полностью совместимо с неподдерживаемыми браузерами, и это задокументированная функция Javascript api.)
В MDN есть пример проверка поддержки локалей и аргументов опций
Мне это нравится, и я рад, что он работает с индийской группировкой цифр.
Это полностью поддерживается по состоянию на 2017 год и должно быть единственно правильным ответом.
Это не дает правильного общепринятого формата для en-ZA / ZAR (Южная Африка), поэтому, если вы находитесь в отдаленном регионе, вы можете зависеть от того, каким, по мнению постороннего, должен быть ваш формат.
@avenmore работает с последними версиями Chrome / Firefox / Safari. Ненавижу спрашивать ... но в каком браузере и какой версии вы тестируете?
Последний и самый лучший :) FF69, Chrome76 и т. д. «2 500,00 рэнд» - это не то, что мы здесь используем, оно должно быть «2 500,00 рэндов», то же самое, что и en-GB.
@avenmore ... интересно ... Я провел небольшое расследование и TL; DR; запятая - официальный десятичный разделитель для Южной Африки. «Когда Южная Африка приняла метрическую систему, она приняла запятую в качестве десятичного разделителя, хотя в ряде домашних стилей, включая некоторые англоязычные газеты, такие как The Sunday Times, по-прежнему используется точка» - en.wikipedia.org/wiki/Decimal_separator. Однако вы можете переключать форматы с помощью (2500).toLocaleString("en-GB", {style: "currency", currency: "ZAR", minimumFractionDigits: 2}).
@Nick Grealy Спасибо за расследование, это проклятие южноафриканских программистов - разрывать вещи после неожиданной запятой. Я попробовал параметры, которые вы предлагаете, но в результате получилось «2500 рэндов», что тоже неприемлемо.
minimumFractionDigits: 2 именно то, что я искал!
Вот краткий и лучший способ конвертировать числа в денежный формат:
function toCurrency(amount){
return amount.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, ",");
}
// usage: toCurrency(3939920.3030);
Ваше здоровье! Анунай
toCurrency('123456.7890') возвращает 123,456.7,890. ИМХО, в десятичных разрядах не должно быть запятых. В остальном выглядит хорошо!
Вот несколько решений, все проходят тестовый набор, тестовый набор и тестовый тест включены. Если вы хотите скопировать и вставить для тестирования, попробуйте Этот Gist.
Основываться на https://stackoverflow.com/a/14428340/1877620, но исправить, если нет десятичной точки.
if (typeof Number.prototype.format === 'undefined') {
Number.prototype.format = function (precision) {
if (!isFinite(this)) {
return this.toString();
}
var a = this.toFixed(precision).split('.');
a[0] = a[0].replace(/\d(?=(\d{3})+$)/g, '$&,');
return a.join('.');
}
}
if (typeof Number.prototype.format === 'undefined') {
Number.prototype.format = function (precision) {
if (!isFinite(this)) {
return this.toString();
}
var a = this.toFixed(precision).split('.'),
// skip the '-' sign
head = Number(this < 0);
// skip the digits that's before the first thousands separator
head += (a[0].length - head) % 3 || 3;
a[0] = a[0].slice(0, head) + a[0].slice(head).replace(/\d{3}/g, ',$&');
return a.join('.');
};
}
if (typeof Number.prototype.format === 'undefined') {
Number.prototype.format = function (precision) {
if (!isFinite(this)) {
return this.toString();
}
var a = this.toFixed(precision).split('.');
a[0] = a[0]
.split('').reverse().join('')
.replace(/\d{3}(?=\d)/g, '$&,')
.split('').reverse().join('');
return a.join('.');
};
}
if (typeof Number.prototype.format === 'undefined') {
Number.prototype.format = function (precision) {
if (!isFinite(this)) {
return this.toString();
}
var a = this.toFixed(precision).split('');
a.push('.');
var i = a.indexOf('.') - 3;
while (i > 0 && a[i-1] !== '-') {
a.splice(i, 0, ',');
i -= 3;
}
a.pop();
return a.join('');
};
}
console.info('======== Demo ========')
console.info(
(1234567).format(0),
(1234.56).format(2),
(-1234.56).format(0)
);
var n = 0;
for (var i=1; i<20; i++) {
n = (n * 10) + (i % 10)/100;
console.info(n.format(2), (-n).format(2));
}
Если нам нужен специальный разделитель тысяч или десятичный разделитель, используйте replace():
123456.78.format(2).replace(',', ' ').replace('.', ' ');
function assertEqual(a, b) {
if (a !== b) {
throw a + ' !== ' + b;
}
}
function test(format_function) {
console.info(format_function);
assertEqual('NaN', format_function.call(NaN, 0))
assertEqual('Infinity', format_function.call(Infinity, 0))
assertEqual('-Infinity', format_function.call(-Infinity, 0))
assertEqual('0', format_function.call(0, 0))
assertEqual('0.00', format_function.call(0, 2))
assertEqual('1', format_function.call(1, 0))
assertEqual('-1', format_function.call(-1, 0))
// decimal padding
assertEqual('1.00', format_function.call(1, 2))
assertEqual('-1.00', format_function.call(-1, 2))
// decimal rounding
assertEqual('0.12', format_function.call(0.123456, 2))
assertEqual('0.1235', format_function.call(0.123456, 4))
assertEqual('-0.12', format_function.call(-0.123456, 2))
assertEqual('-0.1235', format_function.call(-0.123456, 4))
// thousands separator
assertEqual('1,234', format_function.call(1234.123456, 0))
assertEqual('12,345', format_function.call(12345.123456, 0))
assertEqual('123,456', format_function.call(123456.123456, 0))
assertEqual('1,234,567', format_function.call(1234567.123456, 0))
assertEqual('12,345,678', format_function.call(12345678.123456, 0))
assertEqual('123,456,789', format_function.call(123456789.123456, 0))
assertEqual('-1,234', format_function.call(-1234.123456, 0))
assertEqual('-12,345', format_function.call(-12345.123456, 0))
assertEqual('-123,456', format_function.call(-123456.123456, 0))
assertEqual('-1,234,567', format_function.call(-1234567.123456, 0))
assertEqual('-12,345,678', format_function.call(-12345678.123456, 0))
assertEqual('-123,456,789', format_function.call(-123456789.123456, 0))
// thousands separator and decimal
assertEqual('1,234.12', format_function.call(1234.123456, 2))
assertEqual('12,345.12', format_function.call(12345.123456, 2))
assertEqual('123,456.12', format_function.call(123456.123456, 2))
assertEqual('1,234,567.12', format_function.call(1234567.123456, 2))
assertEqual('12,345,678.12', format_function.call(12345678.123456, 2))
assertEqual('123,456,789.12', format_function.call(123456789.123456, 2))
assertEqual('-1,234.12', format_function.call(-1234.123456, 2))
assertEqual('-12,345.12', format_function.call(-12345.123456, 2))
assertEqual('-123,456.12', format_function.call(-123456.123456, 2))
assertEqual('-1,234,567.12', format_function.call(-1234567.123456, 2))
assertEqual('-12,345,678.12', format_function.call(-12345678.123456, 2))
assertEqual('-123,456,789.12', format_function.call(-123456789.123456, 2))
}
console.info('======== Testing ========');
test(Number.prototype.format);
test(Number.prototype.format1);
test(Number.prototype.format2);
test(Number.prototype.format3);
function benchmark(f) {
var start = new Date().getTime();
f();
return new Date().getTime() - start;
}
function benchmark_format(f) {
console.info(f);
time = benchmark(function () {
for (var i = 0; i < 100000; i++) {
f.call(123456789, 0);
f.call(123456789, 2);
}
});
console.info(time.format(0) + 'ms');
}
// if not using async, browser will stop responding while running.
// this will create a new thread to benchmark
async = [];
function next() {
setTimeout(function () {
f = async.shift();
f && f();
next();
}, 10);
}
console.info('======== Benchmark ========');
async.push(function () { benchmark_format(Number.prototype.format); });
next();
Улучшено по сравнению с вашим методом 2. измените значение var a = this.toFixed (precision) .split ('.') На var multiplier = Math.pow (10, precision + 1), wholeNumber = Math.floor (this * multiplier) ; var a = Math.round (wholeNumber / 10) * 10 / множитель; если (String (a) .indexOf ('.') <1) {a + = '.00'; } a = String (a) .split ('.'), не используйте toFixed, потому что он содержит ошибки.
console.info (parseFloat ('4.835'). toFixed (2)); > 4.83 console.info (parseFloat ('54 .835 '). ToFixed (2)); > 54,84 console.info (parseFloat ('454.835'). ToFixed (2)); > 454,83 console.info (parseFloat ('8454.835'). ToFixed (2)); > 8454,83 десятичная дробь всех этих значений должна быть 0,84, а не 0,83
Функция для обработки вывода валюты, включая негативы.
Выходной образец:
5,23 млрд руб.
- 5,23 доллара США
function formatCurrency(total) {
var neg = false;
if (total < 0) {
neg = true;
total = Math.abs(total);
}
return (neg ? "-$" : '$') + parseFloat(total, 10).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, ",").toString();
}
Код от Jonathan M кажется мне сложным, поэтому я переписал его и получил около 30% на FF v30 и 60% на повышении скорости Chrome v35 (http://jsperf.com/number-formating2):
Number.prototype.formatNumber = function(decPlaces, thouSeparator, decSeparator) {
decPlaces = isNaN(decPlaces = Math.abs(decPlaces)) ? 2 : decPlaces;
decSeparator = decSeparator == undefined ? "." : decSeparator;
thouSeparator = thouSeparator == undefined ? "," : thouSeparator;
var n = this.toFixed(decPlaces);
if (decPlaces) {
var i = n.substr(0, n.length - (decPlaces + 1));
var j = decSeparator + n.substr(-decPlaces);
} else {
i = n;
j = '';
}
function reverse(str) {
var sr = '';
for (var l = str.length - 1; l >= 0; l--) {
sr += str.charAt(l);
}
return sr;
}
if (parseInt(i)) {
i = reverse(reverse(i).replace(/(\d{3})(?=\d)/g, "" + thouSeparator));
}
return i+j;
};
Использование:
var sum = 123456789.5698;
var formatted = '$' + sum.formatNumber(2,',','.'); // "3,456,789.57"
Мне нравится просто:
function formatPriceUSD(price) {
var strPrice = price.toFixed(2).toString();
var a = strPrice.split('');
if (price > 1000000000)
a.splice(a.length - 12, 0, ',');
if (price > 1000000)
a.splice(a.length - 9, 0, ',');
if (price > 1000)
a.splice(a.length - 6, 0, ',');
return '$' + a.join("");
}
var number = 3500;
alert(new Intl.NumberFormat().format(number));
// → "3,500" if in US English locale
или phpjs.com/functions/number_format
Просил решение JS!
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat Пример: использование локалей
В этом примере показаны некоторые варианты локализованных числовых форматов. Чтобы получить формат языка, используемого в пользовательском интерфейсе вашего приложения, обязательно укажите этот язык (и, возможно, некоторые резервные языки) с помощью аргумента locales:
var number = 123456.789;
// German uses comma as decimal separator and period for thousands console.info(new Intl.NumberFormat('de-DE').format(number)); // → 123.456,789
// Arabic in most Arabic speaking countries uses real Arabic digits console.info(new Intl.NumberFormat('ar-EG').format(number)); // → ١٢٣٤٥٦٫٧٨٩
// India uses thousands/lakh/crore separators console.info(new Intl.NumberFormat('en-IN').format(number));
Если сумма - это число, скажем -123, тогда
amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
создаст строку "-3.00".
Вот полный рабочий пример.
Этот ответ был почти у меня, но мне нужно было округлить его до ближайшей копейки. Это то, что я использовал amount.toLocaleString ('en-GB', {style: 'currency', currency: 'GBP', maximumFractionDigits: 2});
Приведенный выше код округляет до желаемого количества цифр. См. Пример и введите 1,237 в поле ввода.
Кажется, не работает в Safari. Он просто возвращает число в виде строки без какого-либо форматирования.
Документация MDN для всех, кто хотел бы увидеть полный набор опций.
Вау, это действительно отличный ответ. Должно быть наверху.
Если по какой-то причине вам не нужны центы, вы можете изменить десятичную точность с помощью: minimumFractionDigits: 0
@Horacio / Nico - см. Предыдущий ответ: stackoverflow.com/a/18994850/782034
Мне нравится самый короткий ответ VisionN, за исключением случаев, когда мне нужно изменить его для числа без десятичной точки (123 доллара вместо 123 долларов США), он не работает, поэтому вместо быстрого копирования / вставки мне нужно расшифровать загадочный синтаксис регулярного выражения 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)Subst здесь означает
$&), за которым следует запятая.Поскольку мы используем string.replace, весь остальной текст в строке остается прежним, и только найденные цифры (те, за которыми следуют 3,6,9 и т. д. Другие цифры) получают дополнительную запятую.
Таким образом, в числе 1234567,89 цифры 1 и 4 удовлетворяют условию (1234567.89) и заменяются на «1,» и «4,», в результате чего получается 1 234 567,89.
Если нам вообще не нужна десятичная точка в сумме в долларах (например, 123 доллара вместо 123 долларов), мы можем изменить регулярное выражение следующим образом:
var re2 = /\d(?=(\d{3})+$)/g;
Он полагается на конец строки ($) вместо точки (\.), и окончательное выражение будет (обратите внимание также на toFixed(0)):
n.toFixed(0).replace(/\d(?=(\d{3})+$)/g, '$&,');
Это выражение даст
1234567.89 -> 1,234,567
Кроме того, вместо конца строки ($) в регулярном выражении выше вы также можете выбрать границу слова (\b).
Приношу свои извинения заранее, если я неправильно истолковал какую-либо часть обработки регулярных выражений.
После десятичной дроби вам нужны только две (2) цифры, например, предположим, что ваш формат валюты - это 22.2737, в это время вы можете использовать следующее решение для получения результата в этом формате 22.27, функция currencyFormat (num) {return parseFloat (num) .toFixed (2); } var moneyWithDecimal = currencyFormat (22.2737); alert (moneyWithDecimal);
многие ответы содержали полезные идеи, но ни один из них не соответствовал моим потребностям. Итак, я использовал все идеи и построил этот пример:
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, f.e.: var _f_octal= function( v_in,...){
//--------------------------------
if ( typeof(fmt)!= = "undefined"){
//...can be extended..., just add the char,f.e."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..., f.e.: 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 включает регулярное выражение;
В-третьих, такой вызов, как «формат (значение, fmt)», неприемлем, потому что: Хотя должна быть возможность форматировать разные коллекции объектов (например, ячейки столбца) с разными масками, я не хочу иметь что-то для обработки строк форматирования в точке обработки. На данный момент я хочу только ИСПОЛЬЗОВАТЬ форматирование, как в
for( var cell in cells){ do_something( cell.col.formatter( cell.value)); }
Какой формат - может быть, он определен в ini, в xml для каждого столбца или где-то еще ..., но анализ и установка форматов или имеет дело с интернационализацией обрабатывается совершенно в другом месте, и там я хочу назначить средство форматирования для коллекции, не думая о проблемах с производительностью:
col.formatter = Format_Numb( _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();
Хотя я что-то тестировал, в коде может быть много ошибок. Так что это не готовый модуль, а просто идея и отправная точка для таких не-js-экспертов, как я. Код содержит множество и мало измененных идей из множества сообщений stackoverflow; извините, я не могу сослаться на все из них, но спасибо всем экспертам.
Уже есть хорошие ответы. Вот простая попытка развлечься:
function currencyFormat(no) {
var ar = (+no).toFixed(2).split('.');
return [
numberFormat(ar[0]|0),
'.',
ar[1]
].join('');
}
function numberFormat(no) {
var str = no + '';
var ar = [];
var i = str.length -1;
while( i >= 0 ) {
ar.push( (str[i-2]||'') + (str[i-1]|| '')+ (str[i]|| ''));
i= i-3;
}
return ar.reverse().join(',');
}
Выполните несколько примеров
console.info(
currencyFormat(1),
currencyFormat(1200),
currencyFormat(123),
currencyFormat(9870000),
currencyFormat(12345),
currencyFormat(123456.232)
)
@tggagne правильный. Мое решение ниже не подходит из-за округления с плавающей запятой. А функции toLocaleString не хватает поддержки браузером. Я оставлю нижеприведенные комментарии в целях архивирования того, что НЕ делать. :)
(Старое решение) Вместо этого используйте раствор Патрика Дежардена.
Это краткое решение, использующее toLocaleString (), которое поддерживается начиная с версии Javascript 1.0. В этом примере валюта указывается в долларах США, но ее можно переключить на фунты, используя «GBP» вместо «USD».
var formatMoney = function (value) {
// Convert the value to a floating point number in case it arrives as a string.
var numeric = parseFloat(value);
// Specify the local currency.
return numeric.toLocaleString('USD', { style: 'currency', currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
Дополнительные сведения см. В https://marcoscaceres.github.io/jsi18n/#localize_currency.
Не согласовано во всех браузерах: /
Спасибо за предупреждение @godmode. С какими браузерами вы столкнулись с проблемами?
В Safari 8.0.6 не было обрезки десятичных знаков, вставки символа «$» или добавления запятых.
Возникла идея использовать toLocaleString (), но упала на поплавок. Как отмечалось ранее, валюта никогда не должна храниться в плавающем состоянии.
Спасибо @tggagne, вы правы. Плохой контроль с моей стороны.
55 ответов явно напрашиваются на еще один
function centsToDollaString(x){
var cents = x + ""
while(cents.length < 4){
cents = "0" + cents;
}
var dollars = cents.substr(0,cents.length - 2)
var decimal = cents.substr(cents.length - 2, 2)
while(dollars.length % 3 != 0){
dollars = "0" + dollars;
}
str = dollars.replace(/(\d{3})(?=\d)/g, "" + ",").replace(/^0*(?=.)/,"");
return "$" + str + "." + decimal;
}
Я хочу внести свой вклад в это:
function toMoney(amount) {
neg = amount.charAt(0);
amount= amount.replace(/\D/g, '');
amount= amount.replace(/\./g , '');
amount= amount.replace(/\-/g, '');
var numAmount = new Number(amount);
amount= numAmount .toFixed(0).replace(/./g, function(c, i, a) {
return i > 0 && c !== "," && (a.length - i) % 3 === 0 ? "." + c : c;
});
if (neg == '-')
return neg+amount;
else
return amount;
}
Это позволяет вам преобразовывать числа в текстовое поле, в которое вы можете вводить только числа (рассмотрите этот сценарий).
Это очистит текстовое поле, в котором предполагается использовать только числа, даже если вы вставляете строку с цифрами и буквами или любым символом.
<html>
<head>
<script language= = "Javascript">
function isNumber(evt) {
var theEvent = evt || window.event;
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode(key);
if (key.length == 0) return;
var regex = /^[0-9\-\b]+$/;
if (!regex.test(key)) {
theEvent.returnValue = false;
if (theEvent.preventDefault) theEvent.preventDefault();
}
}
function toMoney(amount) {
neg = amount.charAt(0);
amount= amount.replace(/\D/g, '');
amount= amount.replace(/\./g , '');
amount= amount.replace(/\-/g, '');
var numAmount = new Number(amount);
amount= numAmount .toFixed(0).replace(/./g, function(c, i, a) {
return i > 0 && c !== "," && (a.length - i) % 3 === 0 ? "." + c : c;
});
if (neg == '-')
return neg+amount;
else
return amount;
}
function clearText(inTxt, newTxt, outTxt) {
inTxt = inTxt.trim();
newTxt = newTxt.trim();
if (inTxt == '' || inTxt == newTxt)
return outTxt;
return inTxt;
}
function fillText(inTxt, outTxt) {
inTxt = inTxt.trim();
if (inTxt != '')
outTxt = inTxt;
return outTxt;
}
</script>
</head>
<body>
$ <input name=reca2 id=reca2 type=text value = "0" onFocus = "this.value = clearText(this.value, '0', '');" onblur = "this.value = fillText(this.value, '0'); this.value = toMoney(this.value);" onKeyPress = "isNumber(event);" style = "width:80px;" />
</body>
</html>
Я нашел это из: бухгалтерский учет.js. Это очень просто и идеально подходит для моих нужд.
// Default usage:
accounting.formatMoney(12345678); // ,345,678.00
// European formatting (custom symbol and separators), can also use options object as second parameter:
accounting.formatMoney(4999.99, "€", 2, ".", ","); // €4.999,99
// Negative values can be formatted nicely:
accounting.formatMoney(-500000, "£ ", 0); // £ -500,000
// Simple `format` string allows control of symbol position (%v = value, %s = symbol):
accounting.formatMoney(5318008, { symbol: "GBP", format: "%v %s" }); // 5,318,008.00 GBP
// Euro currency symbol to the right
accounting.formatMoney(5318008, {symbol: "€", precision: 2, thousand: ".", decimal : ",", format: "%v%s"}); // 1.008,00€ $('#price').val( accounting.formatMoney(OOA, { symbol: "€", precision: 2,thousand: ".", decimal :",",format: "%v%s" } ) ); - показать 1.000,00 E
toLocaleString - это хорошо, но работает не во всех браузерах. Обычно я использую currencyFormatter.js (https://osrec.github.io/currencyFormatter.js/). Он довольно легкий и содержит все определения валюты и локали прямо из коробки. Он также хорош для форматирования необычно отформатированных валют, таких как INR (который группирует числа в лакхах и крорах и т. д.). Также никаких зависимостей!
OSREC.CurrencyFormatter.format(2534234, { currency: 'INR' });
// Returns ₹ 25,34,234.00
OSREC.CurrencyFormatter.format(2534234, { currency: 'EUR' });
// Returns 2.534.234,00 €
OSREC.CurrencyFormatter.format(2534234, { currency: 'EUR', locale: 'fr' });
// Returns 2 534 234,00 €
Ничего подобного не видел. Он краток, прост для понимания и не полагается на какие-либо излишне сложные регулярные выражения.
function moneyFormat(price, sign = '$') {
const pieces = parseFloat(price).toFixed(2).split('')
let ii = pieces.length - 3
while ((ii-=3) > 0) {
pieces.splice(ii, 0, ',')
}
return sign + pieces.join('')
}
console.info(
moneyFormat(100),
moneyFormat(1000),
moneyFormat(10000.00),
moneyFormat(1000000000000000000)
)Вот версия с дополнительными параметрами в окончательном выводе, позволяющая форматировать разные валюты в разных форматах местности.
// higher order function that takes options then a price and will return the formatted price
const makeMoneyFormatter = ({
sign = '$',
delimiter = ',',
decimal = '.',
append = false,
precision = 2,
round = true,
custom
} = {}) => value => {
const e = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]
value = round
? (Math.round(value * e[precision]) / e[precision])
: parseFloat(value)
const pieces = value
.toFixed(precision)
.replace('.', decimal)
.split('')
let ii = pieces.length - (precision ? precision + 1 : 0)
while ((ii-=3) > 0) {
pieces.splice(ii, 0, delimiter)
}
if (typeof custom === 'function') {
return custom({
sign,
float: value,
value: pieces.join('')
})
}
return append
? pieces.join('') + sign
: sign + pieces.join('')
}
// create currency converters with the correct formatting options
const formatDollar = makeMoneyFormatter()
const formatPound = makeMoneyFormatter({
sign: '£',
precision: 0
})
const formatEuro = makeMoneyFormatter({
sign: '€',
delimiter: '.',
decimal: ',',
append: true
})
const customFormat = makeMoneyFormatter({
round: false,
custom: ({ value, float, sign }) => `SALE:$${value}USD`
})
console.info(
formatPound(1000),
formatDollar(10000.0066),
formatEuro(100000.001),
customFormat(999999.555)
)Отличный фрагмент кода, спасибо. Однако будьте осторожны, так как это не будет работать в IE, потому что параметры по умолчанию не поддерживаются, а «const» и «let» не поддерживаются в <IE11. Используйте это, чтобы исправить: + moneyFormat: function (price, sign) {+ if (! Sign) sign = '$'; + piece = parseFloat (цена) .toFixed (2) .split ('') + var ii = piece.length - 3
Не беспокойся @CharlieDalsass. Я бы рекомендовал использовать babel, чтобы скомпилировать его до ES5 для производственного кода.
Но как сделать евро валютой? 1.000,00 евро?
@YumYumYum Я добавил полный пример с большим количеством параметров форматирования, чтобы обеспечить большую гибкость.
Мне было сложно найти простую библиотеку для работы с датой и валютой, поэтому я создал свою: https://github.com/dericeira/slimFormatter.js
Просто как тот:
var number = slimFormatter.currency(2000.54);
Вот простой форматтер в vanilla JS:
function numberFormatter (num) {
console.info(num)
var wholeAndDecimal = String(num.toFixed(2)).split(".");
console.info(wholeAndDecimal)
var reversedWholeNumber = Array.from(wholeAndDecimal[0]).reverse();
var formattedOutput = [];
reversedWholeNumber.forEach( (digit, index) => {
formattedOutput.push(digit);
if ((index + 1) % 3 === 0 && index < reversedWholeNumber.length - 1) {
formattedOutput.push(",");
}
})
formattedOutput = formattedOutput.reverse().join('') + "." + wholeAndDecimal[1];
return formattedOutput;
}
Потому что каждая проблема заслуживает решения в одну строку:
Number.prototype.formatCurrency = function() { return this.toFixed(2).toString().split(/[-.]/).reverse().reduceRight(function (t, c, i) { return (i == 2) ? '-' + t : (i == 1) ? t + c.replace(/(\d)(?=(\d{3})+$)/g, ',') : t + '.' + c; }, '$'); }
Это достаточно легко изменить для разных языков, просто замените «$ 1» на «$ 1». и '.' в ',' поменять местами и. в числах, а символ валюты можно изменить, изменив знак «$» в конце.
Или, если у вас есть ES6, вы можете просто объявить функцию со значениями по умолчанию:
Number.prototype.formatCurrency = function(thou = ',', dec = '.', sym = '$') { return this.toFixed(2).toString().split(/[-.]/).reverse().reduceRight(function (t, c, i) { return (i == 2) ? '-' + t : (i == 1) ? t + c.replace(/(\d)(?=(\d{3})+$)/g, '' + thou) : t + dec + c; }, sym); }
console.info((4215.57).formatCurrency())
,215.57
console.info((4216635.57).formatCurrency('.', ','))
.216.635,57
console.info((4216635.57).formatCurrency('.', ',', "\u20AC"))
€4.216.635,57
Да, и это работает и для отрицательных чисел:
console.info((-6635.574).formatCurrency('.', ',', "\u20AC"))
-€6.635,57
console.info((-1066.507).formatCurrency())
-,066.51
И, конечно, вам не обязательно иметь символ валюты.
console.info((1234.586).formatCurrency(',','.',''))
1,234.59
console.info((-7890123.456).formatCurrency(',','.',''))
-7,890,123.46
console.info((1237890.456).formatCurrency('.',',',''))
1.237.890,46
Я хотел ванильное решение javascript, которое автоматически возвращало десятичную часть.
function formatDollar(amount) {
var dollar = Number(amount).toLocaleString("us", "currency");
//decimals
var arrAmount = dollar.split(".");
if (arrAmount.length==2) {
var decimal = arrAmount[1];
if (decimal.length==1) {
arrAmount[1] += "0";
}
}
if (arrAmount.length==1) {
arrAmount.push("00");
}
return "$" + arrAmount.join(".");
}
console.info(formatDollar("1812.2");
Number(value)
.toFixed(2)
.replace(/(\d)(?=(\d{3})+(?!\d))/g, ",")Пожалуйста, найдите в приведенном ниже коде то, что я разработал для поддержки интернационализации. Может кому-нибудь помочь. Он форматирует данное числовое значение в формат, специфичный для языка. В данном примере я использовал ‘En’, пока тестировал ‘Es’, ‘Fr’ и другие страны, где формат меняется. Он не только не позволяет пользователю вводить символы, но и форматирует значение при выводе табуляции. Созданы компоненты для формата Число, а также для формата Десятичная дробь. Помимо этого были созданы функции parseNumber (значение, языковой стандарт) и parseDecimal (значение, языковой стандарт), которые будут анализировать отформатированные данные для любых других бизнес-целей. Указанная функция примет форматированные данные и вернет неформатированное значение. Я использовал плагин валидатора JQuery в приведенном ниже общем коде.
HTML:
<tr>
<td>
<label class = "control-label">
Number Field:
</label>
<div class = "inner-addon right-addon">
<input type = "text" id = "numberField"
name = "numberField"
class = "form-control"
autocomplete = "off"
maxlength = "17"
data-rule-required = "true"
data-msg-required = "Cannot be blank."
data-msg-maxlength = "Exceeding the maximum limit of 13 digits. Example: 1234567890123"
data-rule-numberExceedsMaxLimit = "en"
data-msg-numberExceedsMaxLimit = "Exceeding the maximum limit of 13 digits. Example: 1234567890123"
onkeydown = "return isNumber(event, 'en')"
onkeyup = "return updateField(this)"
onblur = "numberFormatter(this,
'en',
'Invalid character(s) found. Please enter valid characters.')">
</div>
</td>
</tr>
<tr>
<td>
<label class = "control-label">
Decimal Field:
</label>
<div class = "inner-addon right-addon">
<input type = "text" id = "decimalField"
name = "decimalField"
class = "form-control"
autocomplete = "off"
maxlength = "20"
data-rule-required = "true"
data-msg-required = "Cannot be blank."
data-msg-maxlength = "Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
data-rule-decimalExceedsMaxLimit = "en"
data-msg-decimalExceedsMaxLimit = "Exceeding the maximum limit of 16 digits. Example: 1234567890123.00"
onkeydown = "return isDecimal(event, 'en')"
onkeyup = "return updateField(this)"
onblur = "decimalFormatter(this,
'en',
'Invalid character(s) found. Please enter valid characters.')">
</div>
</td>
</tr>
JavaScript:
/*
* @author: dinesh.lomte
*/
/* Holds the maximum limit of digits to be entered in number field. */
var numericMaxLimit = 13;
/* Holds the maximum limit of digits to be entered in decimal field. */
var decimalMaxLimit = 16;
/**
*
* @param {type} value
* @param {type} locale
* @returns {Boolean}
*/
parseDecimal = function(value, locale) {
value = value.trim();
if (isNull(value)) {
return 0.00;
}
if (isNull(locale)) {
return value;
}
if (getNumberFormat(locale)[0] === '.') {
value = value.replace(/\./g, '');
} else {
value = value.replace(
new RegExp(getNumberFormat(locale)[0], 'g'), '');
}
if (getNumberFormat(locale)[1] === ',') {
value = value.replace(
new RegExp(getNumberFormat(locale)[1], 'g'), '.');
}
return value;
};
/**
*
* @param {type} element
* @param {type} locale
* @param {type} nanMessage
* @returns {Boolean}
*/
decimalFormatter = function (element, locale, nanMessage) {
showErrorMessage(element.id, false, null);
if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
return true;
}
var value = element.value.trim();
value = value.replace(/\s/g, '');
value = parseDecimal(value, locale);
var numberFormatObj = new Intl.NumberFormat(locale,
{ minimumFractionDigits: 2,
maximumFractionDigits: 2
}
);
if (numberFormatObj.format(value) === 'NaN') {
showErrorMessage(element.id, true, nanMessage);
setFocus(element.id);
return false;
}
element.value =
numberFormatObj.format(value);
return true;
};
/**
*
* @param {type} element
* @param {type} locale
* @param {type} nanMessage
* @returns {Boolean}
*/
numberFormatter = function (element, locale, nanMessage) {
showErrorMessage(element.id, false, null);
if (isNull(element.id) || isNull(element.value) || isNull(locale)) {
return true;
}
var value = element.value.trim();
var format = getNumberFormat(locale);
if (hasDecimal(value, format[1])) {
showErrorMessage(element.id, true, nanMessage);
setFocus(element.id);
return false;
}
value = value.replace(/\s/g, '');
value = parseNumber(value, locale);
var numberFormatObj = new Intl.NumberFormat(locale,
{ minimumFractionDigits: 0,
maximumFractionDigits: 0
}
);
if (numberFormatObj.format(value) === 'NaN') {
showErrorMessage(element.id, true, nanMessage);
setFocus(element.id);
return false;
}
element.value =
numberFormatObj.format(value);
return true;
};
/**
*
* @param {type} id
* @param {type} flag
* @param {type} message
* @returns {undefined}
*/
showErrorMessage = function(id, flag, message) {
if (flag) {
// only add if not added
if ($('#'+id).parent().next('.app-error-message').length === 0) {
var errorTag = '<div class=\'app-error-message\'>' + message + '</div>';
$('#'+id).parent().after(errorTag);
}
} else {
// remove it
$('#'+id).parent().next(".app-error-message").remove();
}
};
/**
*
* @param {type} id
* @returns
*/
setFocus = function(id) {
id = id.trim();
if (isNull(id)) {
return;
}
setTimeout(function() {
document.getElementById(id).focus();
}, 10);
};
/**
*
* @param {type} value
* @param {type} locale
* @returns {Array}
*/
parseNumber = function(value, locale) {
value = value.trim();
if (isNull(value)) {
return 0;
}
if (isNull(locale)) {
return value;
}
if (getNumberFormat(locale)[0] === '.') {
return value.replace(/\./g, '');
}
return value.replace(
new RegExp(getNumberFormat(locale)[0], 'g'), '');
};
/**
*
* @param {type} locale
* @returns {Array}
*/
getNumberFormat = function(locale) {
var format = [];
var numberFormatObj = new Intl.NumberFormat(locale,
{ minimumFractionDigits: 2,
maximumFractionDigits: 2
}
);
var value = numberFormatObj.format('132617.07');
format[0] = value.charAt(3);
format[1] = value.charAt(7);
return format;
};
/**
*
* @param {type} value
* @param {type} fractionFormat
* @returns {Boolean}
*/
hasDecimal = function(value, fractionFormat) {
value = value.trim();
if (isNull(value) || isNull(fractionFormat)) {
return false;
}
if (value.indexOf(fractionFormat) >= 1) {
return true;
}
};
/**
*
* @param {type} event
* @param {type} locale
* @returns {Boolean}
*/
isNumber = function(event, locale) {
var keyCode = event.which ? event.which : event.keyCode;
// Validating if user has pressed shift character
if (keyCode === 16) {
return false;
}
if (isNumberKey(keyCode)) {
return true;
}
var numberFormatter = [32, 110, 188, 190];
if (keyCode === 32
&& isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
return true;
}
if (numberFormatter.indexOf(keyCode) >= 0
&& getNumberFormat(locale)[0] === getFormat(keyCode)) {
return true;
}
return false;
};
/**
*
* @param {type} event
* @param {type} locale
* @returns {Boolean}
*/
isDecimal = function(event, locale) {
var keyCode = event.which ? event.which : event.keyCode;
// Validating if user has pressed shift character
if (keyCode === 16) {
return false;
}
if (isNumberKey(keyCode)) {
return true;
}
var numberFormatter = [32, 110, 188, 190];
if (keyCode === 32
&& isNull(getNumberFormat(locale)[0]) === isNull(getFormat(keyCode))) {
return true;
}
if (numberFormatter.indexOf(keyCode) >= 0
&& (getNumberFormat(locale)[0] === getFormat(keyCode)
|| getNumberFormat(locale)[1] === getFormat(keyCode))) {
return true;
}
return false;
};
/**
*
* @param {type} keyCode
* @returns {Boolean}
*/
isNumberKey = function(keyCode) {
if ((keyCode >= 48 && keyCode <= 57)
|| (keyCode >= 96 && keyCode <= 105)) {
return true;
}
var keys = [8, 9, 13, 35, 36, 37, 39, 45, 46, 109, 144, 173, 189];
if (keys.indexOf(keyCode) !== -1) {
return true;
}
return false;
};
/**
*
* @param {type} keyCode
* @returns {JSON@call;parse.numberFormatter.value|String}
*/
getFormat = function(keyCode) {
var jsonString = '{"numberFormatter" : [{"key":"32", "value":" ", "description":"space"}, {"key":"188", "value":",", "description":"comma"}, {"key":"190", "value":".", "description":"dot"}, {"key":"110", "value":".", "description":"dot"}]}';
var jsonObject = JSON.parse(jsonString);
for (var key in jsonObject.numberFormatter) {
if (jsonObject.numberFormatter.hasOwnProperty(key)
&& keyCode === parseInt(jsonObject.numberFormatter[key].key)) {
return jsonObject.numberFormatter[key].value;
}
}
return '';
};
/**
*
* @type String
*/
var jsonString = '{"shiftCharacterNumberMap" : [{"char":")", "number":"0"}, {"char":"!", "number":"1"}, {"char":"@", "number":"2"}, {"char":"#", "number":"3"}, {"char":"$", "number":"4"}, {"char":"%", "number":"5"}, {"char":"^", "number":"6"}, {"char":"&", "number":"7"}, {"char":"*", "number":"8"}, {"char":"(", "number":"9"}]}';
/**
*
* @param {type} value
* @returns {JSON@call;parse.shiftCharacterNumberMap.number|String}
*/
getShiftCharSpecificNumber = function(value) {
var jsonObject = JSON.parse(jsonString);
for (var key in jsonObject.shiftCharacterNumberMap) {
if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
&& value === jsonObject.shiftCharacterNumberMap[key].char) {
return jsonObject.shiftCharacterNumberMap[key].number;
}
}
return '';
};
/**
*
* @param {type} value
* @returns {Boolean}
*/
isShiftSpecificChar = function(value) {
var jsonObject = JSON.parse(jsonString);
for (var key in jsonObject.shiftCharacterNumberMap) {
if (jsonObject.shiftCharacterNumberMap.hasOwnProperty(key)
&& value === jsonObject.shiftCharacterNumberMap[key].char) {
return true;
}
}
return false;
};
/**
*
* @param {type} element
* @returns {undefined}
*/
updateField = function(element) {
var value = element.value;
for (var index = 0; index < value.length; index++) {
if (!isShiftSpecificChar(value.charAt(index))) {
continue;
}
element.value = value.replace(
value.charAt(index),
getShiftCharSpecificNumber(value.charAt(index)));
}
};
/**
*
* @param {type} value
* @param {type} element
* @param {type} params
*/
jQuery.validator.addMethod('numberExceedsMaxLimit', function(value, element, params) {
value = parseInt(parseNumber(value, params));
if (value.toString().length > numericMaxLimit) {
showErrorMessage(element.id, false, null);
setFocus(element.id);
return false;
}
return true;
}, 'Exceeding the maximum limit of 13 digits. Example: 1234567890123.');
/**
*
* @param {type} value
* @param {type} element
* @param {type} params
*/
jQuery.validator.addMethod('decimalExceedsMaxLimit', function(value, element, params) {
value = parseFloat(parseDecimal(value, params)).toFixed(2);
if (value.toString().substring(
0, value.toString().lastIndexOf('.')).length > numericMaxLimit
|| value.toString().length > decimalMaxLimit) {
showErrorMessage(element.id, false, null);
setFocus(element.id);
return false;
}
return true;
}, 'Exceeding the maximum limit of 16 digits. Example: 1234567890123.00.');
/**
* @param {type} id
* @param {type} locale
* @returns {boolean}
*/
isNumberExceedMaxLimit = function(id, locale) {
var value = parseInt(parseNumber(
document.getElementById(id).value, locale));
if (value.toString().length > numericMaxLimit) {
setFocus(id);
return true;
}
return false;
};
/**
* @param {type} id
* @param {type} locale
* @returns {boolean}
*/
isDecimalExceedsMaxLimit = function(id, locale) {
var value = parseFloat(parseDecimal(
document.getElementById(id).value, locale)).toFixed(2);
if (value.toString().substring(
0, value.toString().lastIndexOf('.')).length > numericMaxLimit
|| value.toString().length > decimalMaxLimit) {
setFocus(id);
return true;
}
return false;
};
Вы можете использовать Intl изначально следующим образом:
// value: 11.07
Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value)
// result: R$ 11,07
документация: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl
надеюсь это поможет! ;)
Чем это отличается от моего ответа? stackoverflow.com/a/16233919/1000608
Взяв несколько из лучших ответов, я объединил и создал функцию ES6, которая передает eslinter.
export const formatMoney = (
amount,
decimalCount = 2,
decimal = '.',
thousands = ',',
currencySymbol = '$',
) => {
if (typeof Intl === 'object') {
return new Intl.NumberFormat('en-AU', {
style: 'currency',
currency: 'AUD',
}).format(amount);
}
// fallback if Intl is not present.
try {
const negativeSign = amount < 0 ? '-' : '';
const amountNumber = Math.abs(Number(amount) || 0).toFixed(decimalCount);
const i = parseInt(amountNumber, 10).toString();
const j = i.length > 3 ? i.length % 3 : 0;
return (
currencySymbol +
negativeSign +
(j ? i.substr(0, j) + thousands : '') +
i.substr(j).replace(/(\d{3})(?=\d)/g, `${thousands}`) +
(decimalCount
? decimal +
Math.abs(amountNumber - i)
.toFixed(decimalCount)
.slice(2)
: '')
);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
}
return amount;
};
Желательно, не обязательно. Я только что опубликовал ответ, который, как мне кажется, основан на предложениях людей.