Wie formatiert man eine Dezimalzahl?
Die lokale Variabilität dezimaler Zahlenformate
nebst davon abgeleiteter Erscheinungsformen wie
Prozentangaben, Währungsnotierungen,
wissenschaftlicher Notation, etc., stellt eine
Herausforderung bei der Internationalisierung von
Programmen dar. Einerseits müssen unterschiedliche
numerische Formate zur rechnerischen Verarbeitung
vereinheitlicht werden, andererseits sollten numerische
Werte in der jeweiligen Landesform dargestellt werden
können.
Hierzu stellt Java die Klasse DecimalFormat
bereit. Sie ist von NumberFormat
abgeleitet
und ermöglicht die Formulierung von Zeichenmustern,
sog. Pattern, die die jeweilige syntaktische
Erscheinung einer Dezimalzahl definieren. Ein solches
Pattern besteht aus einer Abfolge festgelegter
alphanumerischer Platzhalter, von denen die folgenden
die wichtigsten sind1:
0 | steht für eine zwingend anzuzeigende Ziffer innerhalb der darzustellenden Zahl; ist die Stelle leer, wird eine '0' dargestellt |
# | steht für eine optionale Ziffer innerhalb der darzustellenden Zahl; ist die Stelle leer, wird nichts dargestellt |
. | Dezimaltrenner |
, | Tausendertrenner, genauer: gruppiert die Ziffern zwischen ',' und '.' oder ',' und ',' |
- | Minus-Zeichen |
Mit Hilfe eines Patterns kann das Literal einer vorgegebenen Dezimalzahl in eine beliebige, z.B. auch lokalisierte Form überführt werden. Umgekehrt kann eine solche auch in die in Java gebräuchliche Standardform gewandelt werden.
import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; public class ZahlenFormatieren { public static void main(String[] args) { double d = 12345.678; DecimalFormat df = new DecimalFormat("0,000,000.0#"); String str = df.format(d); System.out.println(df.format(d)); // 0.012.345,68 try { System.out.println(df.parse(str)); // 12345.68 System.out.println(df.parse("12345.678")); // 12345678 } catch (ParseException e) { e.printStackTrace(); } } }
Im Beispiel wird ein DecimalFormat
-Objekt
erzeugt, dem ein Pattern-String an den Konstruktor
übergeben wird [8]. Das Pattern weist neun
obligatorische Stellen mit Tausendertrennern vor dem
Komma und zwei Nachkommastellen auf. An die Methode format()
des Formatters wird jedoch ein double-Wert mit drei
Nachkommastellen und, da es sich um ein double-Literal
und nicht um einen String handelt,
selbstverständlich ohne Tausendertrenner, als
Parameter übergeben. Die Methode liefert einen
String, der dem initialen Pattern entspricht: Die
Tausendertrenner werden verwendet und fehlende Ziffern
mit '0' gefüllt [10].
Beachtenswert ist
darüber hinaus, dass die drei Nachkommastellen
patterngerecht auf zwei gekürzt und dabei gerundet
werden. Die Rundung entspricht dabei in der Standardform
dem Modus der Enumkonstante RoundingMode.HALF_EVEN
.
Soll ein davon abweichender verwendet werden, kann dies
über die Methode DecimalFormat#setRoundingMode(RoundingMode mode)
geändert werden.
Wird der formatierte Zahlenstring durch parse()
wieder in die double-Normalform rückübersetzt,
so wird als Dezimaltrenner wieder '.' verwendet und die
Tausendertrenner entfallen, die Rundung bleibt jedoch
erhalten [12].
Große Vorsicht ist angebracht,
wenn durch den Formatter ein extern bereitgestellter
String geparst wird. Entspricht dieser nicht dem
vorgegebenen Pattern, so wird ab dem ersten falschen
Zeichen jede Formatierung ignoriert [13]!
Ändern des Pattern-Zeicheninventars
Das Zeicheninventar der initialen Definition eines
Patterns ist weitgehend eingeschränkt und richtet
sich für die gängigsten Zeichen nach der o.a.
Tabelle1. Durch die Klasse
DecimalFormatSymbols
lassen sich diese
jedoch ändern, wie im Folgenden anhand des Dezimal-
und des Tausendertrenners gezeigt.
DecimalFormat df = new DecimalFormat("0,000,000.0#"); DecimalFormatSymbols ds = new DecimalFormatSymbols(); ds.setGroupingSeparator('|'); ds.setDecimalSeparator('_'); df.setDecimalFormatSymbols(ds); //... System.out.println(df.format(d)); // 0|012|345_68
Regionale Pattern
Die Erzeugung des Patterns kann auch mittels einer
Länderkonstante erzeugt werden. Hierzu muss jedoch
statt eines DecimalFormat
-Objektes eines
seiner Superklasse NumberFormat
erzeugt
werden, das später zum DecimalFormat
gecastet wird. Die Objektbildung findet über die
Methode getInstance()
statt. Ihr wird eine
Konstante der Klasse Locale
als Parameter
übergeben.
NumberFormat nuf = NumberFormat.getInstance(Locale.JAPAN); if (nuf instanceof DecimalFormat) { System.out.println(((DecimalFormat) nuf).toPattern()); // #,##0.### }
1) Die vollständige Dokumentation
des Patternaufbaus kann in den JavaDocs der Klasse DecimalFormat
nachgeschlagen werden.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.