Zahlenformatierung

Zahlen werden je nach Land unterschiedliche formatiert ausgegeben. Deutschland trennt alle 3 Stellen vor dem Komma mit einem Punkt, die USA nutzen dafür ein Komma. Derartige Besonderheiten werden in der Locale eingefangen, wie man auf einen Ausgabestrom anwenden kann.

Video

Quelltext

#include <iostream>
#include <locale>

int main()
{
    double test = 123456789.1234;

    std::cout.imbue(std::locale("de_DE.UTF-8"));
    std::cout << std::fixed << test << std::endl;

    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << std::fixed << test << std::endl;

    std::cout.imbue(std::locale(""));
    std::cout << std::fixed << test << std::endl;
}

Erklärung

Speziell bei der Ausgabe von Daten an den Nutzer (oder auch im Umkehrschluss beim Einlesen, was aber hier nicht dargestellt ist), ist eine Anpassung an die Kultur des Nutzers relevant. Dazu gehören unter anderem Zahlenformate. C++ kapselt die Gesamtheit der Kulturanpassungen in einer Locale, die mittels imbue() an einen Strom gebunden wird. Die Locale an sich ist nur ein Container, der die spezifischen Aspekte als Facetten-Objekte speichert und auffindbar macht.

Im Beispiel oben werden nacheinander drei verschiedene Locales an den Strom std::cout gebunden. Die std::locale-Objekte werden anhand eines (systemspezifischen) Namens erzeugt. Der erste repräsentiert auf meiner Plattform eine Locale mit deutschen Einstellungen (bspw. das Komma als Dezimaltrenner, der Punkt als Tausendertrennzeichen etc.). Die zweite ist für die Einstellungen für US-Amerikaner zuständig. Der interessanteste (weil vermutlich am häufigsten auftretende) Fall ist die dritte Variante. Ist der Name leer, so soll systemspezifisch die vom Nutzer bevorzugte Locale geladen werden. Unter Unix-artigen Systemen (Linux, OSX etc) wird das über die Umgebungsvariable LANG festgelegt. Die enthält den Namen der zu wählenden Standardlocale. Andere Systeme haben dafür ebenso Möglichkeiten. Will man also ein Programm schreiben, welches sich automatisch an die Einstellungen des Nutzers anpasst, dann ist diese Variante die richtige.

Die eigentliche Zahlenformatierung ist nicht in std::locale realisiert, sondern in der std::numpunct-Facette. Diese bietet Möglichkeiten zur Ermittelung des Tausendertrennzeichens, des Dezimaltrenners, der Positionen der Trennzeichen etc. Das Locale-Objekt speichert lediglich eine Referenz auf die entsprechende Facette. Diese wird vom Ausgabeoperator abgerufen, um die Ausgabe zu realisieren.