【问题标题】:How do you format a fractional percentage with java.text.MessageFormat如何使用 java.text.MessageFormat 格式化小数百分比
【发布时间】:2009-03-30 17:45:03
【问题描述】:

我的百分比被默认的 java.text.MessageFormat 函数截断,你如何格式化百分比而不损失精度?

例子:

String expectedResult = "12.5%";
double fraction = 0.125;

String actualResult = MessageFormat.format("{0,number,percent}", fraction);
assert expectedResult.equals(actualResult) : actualResult +" should be formatted as "+expectedResult;

【问题讨论】:

    标签: java text localization


    【解决方案1】:

    我认为正确的做法如下:

    NumberFormat percentFormat = NumberFormat.getPercentInstance();
    percentFormat.setMaximumFractionDigits(1);
    String result = percentFormat.format(0.125);
    

    它还考虑了内化。例如,在我使用匈牙利语言环境的机器上,我得到了预期的“12.5%”。将 percentFormat 初始化为 NumberFormat.getPercentInstance(Locale.US) 当然会给出“12.5%”。

    【讨论】:

      【解决方案2】:

      看起来像这样:

      String actualResult = MessageFormat.format("{0,number,#.##%}", fraction);
      

      ...正在工作。

      编辑:要查看 # 和 % 是如何解释的,请参阅 java.text.DecimalFormat 的 javadoc。

      编辑 2:是的,国际化是安全的。格式字符串中的点被解释为小数分隔符,而不是硬编码的点。 :-)

      【讨论】:

      • 但是,国际化可能不安全。我不确定。
      • 本地化程序总是有破坏一些格式化字符串的危险,但除此之外我想不出任何其他问题......
      【解决方案3】:

      怎么样

      DecimalFormat f = new DecimalFormat( "###.#" );
      System.out.println( f.format( 12.5 ) );
      

      格式 char '#' 不会将 0 打印为不存在。所以 12.5 ->“12.5”,12.0 ->“12”,而不是“12.0”。您当然可以使用例如设置格式化程序"###,###.##",只有在需要精度时才会显示百位。

      【讨论】:

        【解决方案4】:

        你确实知道"expectedResult == actualResult" 永远是假的,对吧?

        无论如何,我能找到的最佳解决方案是明确设置格式化程序。这是我测试的代码:

        String expectedResult = "12.5%";
        double fraction = 0.125;
        MessageFormat fmt = new MessageFormat("{0,number,percent}");
        NumberFormat nbFmt = NumberFormat.getPercentInstance();
        nbFmt.setMaximumFractionDigits(1); // or 2, or however many you need
        fmt.setFormatByArgumentIndex(0, nbFmt);
        String actualResult = fmt.format(new Object[] {fraction});
        assert expectedResult.equals(actualResult) : actualResult +" is getting rounded off";
        

        【讨论】:

          【解决方案5】:

          如果国际化是一个问题:

          // get locale from somewhere. default is usually a bad idea, especially
          // if running in a app server
          Locale locale = Locale.getDefault();
          NumberFormat fmt = NumberFormat.getPercentInstance(locale);
          // the question requires 1 digit for fractional part
          // therefore set both, minimum and maximum digit count
          fmt.setMinimumFractionDigits(1);
          fmt.setMaximumFractionDigits(1);
          // set grouping, if you expect large values
          // notabene: not all languages use 3 digits per group
          fmt.setGroupingUsed(true);
          // output the example of the original question
          System.out.println(fmt.format(0.125));
          

          百分比数字格式化程序在我知道的语言环境中将一个空格和百分号附加到输出中。我不知道百分号的位置是否在其他语言环境中的数字之前(例如从右到左的语言环境)。

          【讨论】:

            【解决方案6】:

            我的解决方案呈现与给定数字上设置的比例一样多的小数位数。使用许多原始类型和Number 类型进行了单元测试。

            /**
             * Formats the given Number as percentage with necessary precision.
             * This serves as a workaround for {@link NumberFormat#getPercentInstance()} which does not renders fractional
             * digits.
             *
             * @param number
             * @param locale
             *
             * @return
             */
            public static String formatPercentFraction(final Number number, final Locale locale)
            {
                if (number == null)
                    return null;
            
                // get string representation with dot
                final String strNumber = NumberFormat.getNumberInstance(Locale.US).format(number.doubleValue());
                // create exact BigDecimal and convert to get scale
                final BigDecimal dNumber = new BigDecimal(strNumber).multiply(new BigDecimal(100));
            
                final NumberFormat percentScaleFormat = NumberFormat.getPercentInstance(locale);
                percentScaleFormat.setMaximumFractionDigits(Math.max(0, dNumber.scale()));
            
                // convert back for locale percent formatter
                return percentScaleFormat.format(dNumber.multiply(new BigDecimal(0.01)));
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-07-03
              • 2019-12-28
              • 2017-10-03
              • 2015-07-13
              • 2010-12-19
              • 1970-01-01
              • 1970-01-01
              • 2017-10-03
              相关资源
              最近更新 更多