#javascript #number-formatting
#javascript #форматирование чисел
Вопрос:
Я использую Intl.NumberFormat
для форматирования чисел:
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 4,
minimumSignificantDigits: 1,
maximumSignificantDigits: 4
})
formatter.format(0.99999) // results: '1'. desired result: '0.9999'
formatter.format(0.006393555) // results: '0.006394'. desired result: '0.006393'
formatter.format(0.9972620384752073) // results: '0.9973'. desired result: '0.9972'
formatter.format(12345.67) // results: '12,350'. desired result: '12,345.67'
formatter.format(200001) // results: '200,000'. desired result: '200,001'
Как вы можете видеть, числа округляются автоматически, что в моем случае является нежелательным поведением.
Есть ли способ указать форматировщику не округлять? Я не нашел какой-либо опции или комбинации опций для достижения этой цели.
Комментарии:
1. увеличить
maximumSignificantDigits
до числа, которое будет на 1 больше, чем количество десятичных знаков?2. Каков желаемый результат от такого числа
12345.67
?3. Расширение вопроса КИКО — ваш вариант использования только с дробными числами (единственные приведенные примеры)? Если вы будете форматировать значения больше 1, пожалуйста, обновите свой вопрос некоторыми вариантами форматирования с ними.
4. Во всех случаях дробные числа должны сохранять свои дробные цифры до 4 значащих цифр. Так
12345.67
и должно получиться12,345.67
.5. @baba-dev обновил мой ответ на основе ваших последних изменений.
Ответ №1:
Я не думаю, что это возможно с текущей спецификацией, и есть несколько предложений для новой спецификации, но вы все равно можете использовать formatToParts
метод и добавить пользовательскую функцию для форматирования числовых частей по своему усмотрению.
Для вашего первого варианта использования это может выглядеть примерно так:
const trauncateFractionAndFormat = (parts, digits) => {
return parts.map(({ type, value }) => {
if (type !== 'fraction' || !value || value.length < digits) {
return value;
}
let retVal = "";
for (let idx = 0, counter = 0; idx < value.length amp;amp; counter < digits; idx ) {
if (value[idx] !== '0') {
counter ;
}
retVal = value[idx];
}
return retVal;
}).reduce((string, part) => string part);
};
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 20
})
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.99999), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.006393555), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.9972620384752073), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(12345.67), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(20001), 4));
Ответ №2:
NumberFormat всегда будет округляться в большую сторону, но вы можете обойти эту дополнительную функцию.
function roundDownSignificantDigits(number, decimals) {
let significantDigits = (parseInt(number.toExponential().split('e-')[1])) || 0;
let decimalsUpdated = (decimals || 0) significantDigits - 1;
decimals = Math.min(decimalsUpdated, number.toString().length);
return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals));
}
и затем
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 4,
minimumSignificantDigits: 1,
maximumSignificantDigits: 4
})
Результат:
formatter.format(roundDownSignificantDigits(0.99999,4)); // "0.9999"
formatter.format(roundDownSignificantDigits(0.006393555,4)); // "0.006393"
formatter.format(roundDownSignificantDigits(0.9972620384752073,4)); // "0.9972"
Комментарии:
1.Это приведет к сбою для второго тестового примера
0.006393555
, в результате чего"0.0063"
вместо"0.006393"
2. NumberFormat также округляет в меньшую сторону… не просто вверх. смотрите последний пример в моем коде.
3. @краткое изложение я обновил свою функцию roundDownSignificantDigits, и теперь она должна работать просто отлично
Ответ №3:
Иногда приведенные выше решения округляют значение, вот самое простое решение, которое я использую, и оно отлично работает для меня,
let a = "2.2652";// string
let b = 2.2652; // decimal-number
let c = 22200223.26522200225; // decimal-number
let d = 2 // non-decimal
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 20,
minimumSignificantDigits: 1,
maximumSignificantDigits: 20
});
const newFunc = (val)=>{
val = formatter.format((val))
if(val.includes(".")){
let number = val.toString().split(".")[0] "." val.split(".")[1].slice(0, 2)
return number
}else{
return val
}
}
console.log(newFunc(a))
console.log(newFunc(b))
console.log(newFunc(c))
console.log(newFunc(d))
Ответ №4:
Я мог бы получить его с помощью formatToParts. Вы также можете выполнить некоторые трюки с функциями массива javascript, чтобы при необходимости отделить десятичную часть.
export const formatNumberWithoutDecimals = (price) =>
new Intl.NumberFormat(i18n.language, {
minimumFractionDigits: 2,
}).formatToParts(price).reduce((result, part) => (part.type !== "decimal" amp;amp; part.type !== "fraction") ? result part.value : result, "");