【问题标题】:Use Intl.NumberFormat without rounding使用不四舍五入的 Intl.NumberFormat
【发布时间】:2021-01-27 12:25:40
【问题描述】:

我正在使用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'

如您所见,数字会自动四舍五入,这在我的情况下是不受欢迎的行为。

有没有办法告诉格式化程序不要舍入? 我没有found any option 或组合选项来实现这一点。

【问题讨论】:

  • maximumSignificantDigits 增加到比小数位数多1 的数字?
  • 12345.67 这样的数字的期望结果是什么?
  • 扩展 KIKO 的问题 - 您的用例是否仅使用小数(提供的唯一示例)?如果您将格式化大于 1 的值,请使用一些格式化案例更新您的问题。
  • 在所有情况下,小数应保留其小数位数,最多为 4 位有效数字。所以12345.67 应该是12,345.67
  • @baba-dev 根据您的最新更改更新了我的答案。

标签: javascript number-formatting


【解决方案1】:

我可以使用 formatToParts 获得它。如果需要,您还可以执行一些 javascript 数组函数技巧来分离小数部分。

export const formatNumberWithoutDecimals = (price) =>
  new Intl.NumberFormat(i18n.language, {
    minimumFractionDigits: 2,
  }).formatToParts(price).reduce((result, part) => (part.type !== "decimal" && part.type !== "fraction") ? result + part.value : result, "");

【讨论】:

    【解决方案2】:

    我认为在当前规范下这是不可能的,并且有 few proposals for the new spec,但您仍然可以使用 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 && 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));

    【讨论】:

      【解决方案3】:

      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"
      

      【讨论】:

      • 第二个测试用例 0.006393555 将失败,导致 "0.0063" 而不是 "0.006393"
      • NumberFormat 也向下舍入...而不仅仅是向上舍入。请参阅我的代码中的最后一个示例。
      • @concision 我更新了我的函数 roundDownSignificantDigits,现在它应该可以正常工作了
      猜你喜欢
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-04
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多