Die Formatierungsbibliothek in C++20: Der Formatstring
Der Beitrag setzt die Serie zu Formatstrings in C++20 fort und taucht tiefer in die Formatspezifikation ein.
In meinem letzten Artikel habe ich "Softwareentwicklung: Die Formatierungsbibliothek in C++20 [1]" vorgestellt. Heute werde ich tiefer in die Formatspezifikation des Formatstrings eintauchen.
Anfangen möchte ich mit einer kurzen Zusammenfassung des Formatstrings.
- Syntax:
std::format(FormatString, Args)
Der Formatstring FormatString besteht aus
- Gewöhnlichen Zeichen (außer
{
und}
) - Escape-Sequenzen
{{
und}}
, die durch{
und}
ersetzt werden - Ersetzungsfelder
Ein Ersatzfeld hat das Format { }
.
Argument-ID
Man kann eine Argument-ID und einen Doppelpunkt innerhalb des Ersetzungsfeldes verwenden, gefolgt von einer Formatangabe. Beide Komponenten sind optional.
Dank der Argument-ID lassen sich bestimmte Argumente neu anordnen oder ansprechen. Mit der Argument-ID lässt sich der Index der Argumente in Args angeben. Die IDs beginnen mit 0. Wenn keine Argument-ID angegeben ist, werden die Felder in der gleichen Reihenfolge ausgefüllt, in der die Argumente angegeben werden. Entweder müssen alle Ersetzungsfelder eine Argument-ID verwenden oder keine.
// formatArgumentID.cpp
#include <format>
#include <iostream>
#include <string>
int main() {
std::cout << '\n';
std::cout << std::format("{} {}: {}!\n",
"Hello", "World", 2020); // (1)
std::cout << std::format("{1} {0}: {2}!\n",
"World", "Hello", 2020); // (2)
std::cout << std::format("{0} {0} {1}: {2}!\n",
"Hello", "World", 2020); // (3)
std::cout << std::format("{0}: {2}!\n",
"Hello", "World", 2020); // (4)
std::cout << '\n';
}
(1) zeigt die Argumente in der angegebenen Reihenfolge an. Im Gegensatz dazu werden in (2) das erste und das zweite Argument neu angeordnet, in (3) wird das erste Argument zweimal angezeigt und in (4) wird das zweite Argument ignoriert.
Der Vollständigkeit halber ist hier die Ausgabe des Programms:
Die Anwendung des Arguments id mit der Formatspezifikation macht die Formatierung von Text in C++20 sehr leistungsfähig.
Formatspezifikation
Ich werde nicht die formale Formatspezifikation für Datentypen, String-Typen und Chrono-Typen vorstellen. Für Datentypen und std::string finden sich
die vollständigen Details hier: standard format specification [2]. Dementsprechend findet man die Details für Chrono-Typen hier: chrono format specification [3].
Stattdessen stelle ich eine pragmatische Beschreibung des Formatstrings für Datentypen, String-Typen und Chrono-Typen vor.
fill_align(opt) sign(opt) #(opt) 0(opt) width(opt) precision(opt) L(opt) type(opt)
Alle Teile sind optional (opt). In den folgenden Abschnitten gehe ich auf die Features dieser Formatspezifikation genauer ein.
Füllzeichen und Ausrichtung
Das Füllzeichen ist optional (jedes Zeichen außer {
oder }
) und wird von einer Ausrichtungsangabe gefolgt. Um das Füllzeichen zu verwenden, muss man die Ausrichtung angeben.
- Füllzeichen: Standardmäßig wird das Leerzeichen verwendet
- Ausrichtung:
<
: links (Standard für Werte, die keine Zahlen sind)>
: rechts (Standard für Zahlen)^
: zentriert
// formatFillAlign.cpp
#include <format>
#include <iostream>
int main() {
std::cout << '\n';
int num = 2020;
std::cout << std::format("{:6}", num) << '\n';
std::cout << std::format("{:6}", 'x') << '\n';
std::cout << std::format("{:*<6}", 'x') << '\n';
std::cout << std::format("{:*>6}", 'x') << '\n';
std::cout << std::format("{:*^6}", 'x') << '\n';
std::cout << std::format("{:6d}", num) << '\n';
std::cout << std::format("{:6}", true) << '\n';
std::cout << '\n';
}
Die Standardausrichtung hängt von den verwendeten Datentypen ab. Im Gegensatz zum iostream-Operator werden boolesche Werte standardmäßig als true
oder false
dargestellt.
Vorzeichen, #
und 0
Vorzeichen, #
und 0
sind nur gültig, wenn ein Ganzzahl- oder Fließkommatyp verwendet wird.
Das Vorzeichen kann die folgenden Werte haben:
+
: Das Vorzeichen wird für Null und positive Zahlen verwendet.-
: Das Vorzeichen wird nur für negative Zahlen verwendet (Standard).- Leerzeichen: Ein führendes Leerzeichen wird für nicht negative Zahlen verwendet und ein Minuszeichen für negative Zahlen.
// formatSign.cpp
#include <format>
#include <iostream>
int main() {
std::cout << '\n';
std::cout << std::format("{0:},{0:+},{0:-},{0: }", 0) << '\n';
std::cout << std::format("{0:},{0:+},{0:-},{0: }", -0) << '\n';
std::cout << std::format("{0:},{0:+},{0:-},{0: }", 1) << '\n';
std::cout << std::format("{0:},{0:+},{0:-},{0: }", -1) << '\n';
std::cout << '\n';
}
Das #
bewirkt die alternative Form:
- Bei ganzzahligen Datentypen wird das Präfix
0b
,0
oder0x
für binäre, oktale oder hexadezimale dargestellte Typen verwendet. - Für Datentypen mit Fließkommazahlen wird immer ein Dezimalpunkt verwendet.
0
: Auffüllen mit führenden Nullen
// formatAlternate.cpp
#include <format>
#include <iostream>
int main() {
std::cout << '\n';
std::cout << std::format("{:#015}", 0x78) << '\n';
std::cout << std::format("{:#015b}", 0x78) << '\n';
std::cout << std::format("{:#015x}", 0x78) << '\n';
std::cout << '\n';
std::cout << std::format("{:g}", 120.0) << '\n';
std::cout << std::format("{:#g}", 120.0) << '\n';
std::cout << '\n';
}
Wie geht es weiter?
Mit dem Formatbezeichner kann man die Genauigkeit, die Breite und den Datentyp des Wertes angeben. Darüber werde ich in meinem nächsten Artikel schreiben. (rme [4])
URL dieses Artikels:
https://www.heise.de/-9610546
Links in diesem Artikel:
[1] https://www.heise.de/blog/Softwareentwicklung-Die-Formatierungsbibliothek-in-C-20-9602498.html
[2] https://en.cppreference.com/w/cpp/utility/format/formatter#Standard_format_specification
[3] https://en.cppreference.com/w/cpp/chrono/system_clock/formatter#Format_specification
[4] mailto:rme@ix.de
Copyright © 2024 Heise Medien