2009-03-30 9 views
32

Meine Prozentsätze werden durch die Standardfunktion java.text.MessageFormat abgeschnitten. Wie formatiert man einen Prozentsatz, ohne die Genauigkeit zu verlieren?Wie formatiert man einen Bruchteilprozentsatz mit java.text.MessageFormat

Beispiel:

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; 

Antwort

47

sieht wie folgt aus:

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

... arbeitet.

BEARBEITEN: Um zu sehen, wie die # und% interpretiert werden, sehen Sie das Javadoc von java.text.DecimalFormat.

EDIT 2: Und ja, es ist sicher für die Internationalisierung. Der Punkt in Formatzeichenfolge wird als Dezimaltrennzeichen und nicht als fest codierter Punkt interpretiert. :-)

+0

+1, das ist wayyy einfacher als das, was ich getan habe. –

+0

Es ist jedoch möglicherweise nicht sicher für die Internationalisierung. Ich weiß es nicht genau. –

+0

Es besteht immer die Gefahr, dass Lokalisierer einige Formatierungszeichenfolgen brechen, aber ansonsten kann ich an nichts anderes denken ... –

5

Wie wäre es

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

Das Format char '#' nicht 0 als abwesend druckt. Also 12,5 -> "12,5", 12,0 -> "12", nicht "12,0". Sie könnten Ihren Formatierer natürlich mit z. "###, ###. ##", der Hundreth Platz wird nur angezeigt, wenn Sie die Präzision brauchen.

3

Sie erkennen, dass "expectedResult == actualResult" wird immer falsch sein, oder?

Wie auch immer, die beste Lösung, die ich finden kann, ist, den Formatierer explizit zu setzen. Dies ist der Code, den ich getestet:

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"; 
+0

hah, ja. Das tut mir leid. Ich habe das Beispiel korrigiert. – Lorin

48

Ich denke, die richtige Art und Weise, es zu tun ist folgende:

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

Es ist auch Internalisierung berücksichtigt. Zum Beispiel auf meiner Maschine mit ungarischen Locale bekam ich "12,5%" wie erwartet. Die Initialisierung von percentFormat als NumberFormat.getPercentInstance(Locale.US) ergibt "12,5%" natürlich.

+1

In Android funktioniert es wie ein Zauber! Vielen Dank. – Rainbowbreeze

2

Wenn Internationalisierung ist ein Anliegen:

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

Die prozentuale Zahl Formatierer fügt ein Leerzeichen und das Prozentzeichen an den Ausgang in den Gegenden die ich kenne. Ich weiß nicht, ob die Position des Prozentzeichens vor den Ziffern in anderen Gebietsschemas steht (z. B. von rechts nach links).

2

Meine Lösung gibt so viele Nachkommastellen aus, wie der Maßstab für die angegebene Zahl festgelegt wurde. Einheit getestet mit vielen primitiven und Number Typen.

/** 
* 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))); 
} 
Verwandte Themen