web-dev-qa-db-ja.com

Java.text.MessageFormatで小数の割合をどのようにフォーマットしますか

デフォルトの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;
33
Lorin

次のようになります。

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

... 取り組んでいます。

編集:#と%がどのように解釈されるかを確認するには、Java.text.DecimalFormatのjavadocを参照してください。

編集2:そして、はい、それは国際化にとって安全です。フォーマット文字列のドットは、ハードコードされたドットとしてではなく、小数点として解釈されます。 :-)

52
david a.

適切な方法は次のとおりだと思います。

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

また、内部化も考慮します。たとえば、ハンガリー語ロケールのマシンでは、予想どおり「12.5%」になりました。 percentFormatをNumberFormat.getPercentInstance(Locale.US)として初期化すると、もちろん「12.5%」になります。

51
Chei

どう?

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

書式char '#'は、0を不在として出力しません。したがって、12.5-> "12.5"、12.0-> "12"、 "12.0"ではありません。もちろん、たとえば、 "###、###。##"、精度が必要な場合にのみ百合目が表示されます。

6
Steve B.

"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";
3
Michael Myers

私のソリューションは、指定された数値にスケールが設定されているのと同じ数の小数桁をレンダリングします。多くのプリミティブ型および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)));
}
2
djmj

国際化が懸念される場合:

// 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));

パーセント数値フォーマッターは、私が知っているロケールの出力にスペースとパーセント記号を追加します。パーセント記号の位置が他のロケール(たとえば、右から左のロケール)の数字の前にあるかどうかはわかりません。

2
rhjoerg