1. Origine
Il était tard dans la nuit et l'aiguille des heures indiquait doucement onze heures trente, mais mes pensées déferlaient comme une source et je n'arrivais pas à dormir du tout. A cette époque, j'avais hâte de faire quelque chose de significatif, et j'ai décidé de profiter de cette tranquillité pour me calmer et rédiger un guide sur l'utilisation de la bibliothèque fmt.
La bibliothèque fmt est une bibliothèque de formatage C++ efficace et facile à utiliser qui peut nous aider à effectuer facilement le formatage de chaîne, la sortie, la journalisation et d'autres opérations. Dans ce guide, je présenterai l'utilisation de base de la bibliothèque fmt, la syntaxe des chaînes formatées, le mécanisme de gestion des exceptions, etc., dans l'espoir d'aider tout le monde. Commençons!
2. Utilisation de base
Installer la bibliothèque fmt
github : https://github.com/fmtlib/fmt
guide de l'API : https://fmt.dev/latest/api.html
Introduire la bibliothèque fmt dans le projet
- L'ancienne méthode cmake (non recommandée)
mkdir build
cd build
cmake ...
make ou utilisez l'IDE pour ouvrir le fichier projet généré afin de générer la bibliothèque statique correspondante\ - Incluez uniquement les fichiers d'en-tête (il est nécessaire de #define FMT_HEADER_ONLY avant d'inclure les fichiers d'en-tête recommandés)
- fmt/core.h : la fonction de formatage principale de char/UTF-8, prend en charge la vérification au moment de la compilation C++20 et minimise les dépendances.
- fmt/format.h : API de formatage complète, en plus de fonctions de formatage supplémentaires, prend en charge la localisation (prise en charge multilingue).
- fmt/ranges.h : formater les plages et les tuples
- fmt/chrono.h : Formatage de la date et de l'heure.
- fmt/std.h : prise en charge du formatage pour les types de bibliothèques standard C++.
- fmt/compile.h : Compilation de chaînes de format (détection de chaîne de format au moment de la compilation). FMT_STRING(s)
- fmt/color.h : couleur du terminal et style de texte.
- fmt/os.h : fournit une API système.
- fmt/ostream.h : prend en charge std ::ostream.
- fmt/printf.h : prend en charge le formatage printf.
- fmt/xchar.h : prise en charge facultative de wchar_t.
Bonjour le monde
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include <string>
int main()
{
// {} 占位符,可以占位int float double ....
std::string world = fmt::format("Hello {}", "World");
fmt::print("{}", world);
}
3. Syntaxe de formatage des caractères
Les fonctions de formatage telles que fmt::format() et fmt::print() utilisent toutes la même syntaxe, qui est un « champ de remplacement » entouré de {}.
Tout ce qui n'est pas entouré d'accolades est traité comme du texte littéral et sera copié dans la sortie sans modification. Si vous devez inclure une accolade dans un texte littéral, vous pouvez l'échapper en répétant l'accolade : { {
et }}.
Dans la plupart des cas, la syntaxe est similaire au format printf, mais {} est ajouté et : est utilisé à la place de %. Par exemple, "%03.2f" peut être converti en "{:03.2f}", en remplaçant simplement % par {}, mais fmt est plus puissant. Le format de sortie est le suivant : remplacement_field ::= "{" [
arg_id
] [":" (format_spec | chrono_format_spec)] « } » // Caractère de remplacement = {[parameter id]:[format_spec] | [chrono_format_spec]} arg_id ::= entier |
identifiant // Entier 0-9 az AZ, ce qui suit indique lequel signifie quoi
entier ::= chiffre+
chiffre ::= « 0 »…« 9 »
identifiant ::= id_start id_continue*
id_start ::= « a »… « z » | « A »… « Z » | « _ "
id_continue ::= id_start | chiffre\
Le format de remplacement utilise " : comme délimiteur. Celui avant : : représente l'identifiant du paramètre, qui fait référence à l'ordre des paramètres. Il peut être 1, 2, 3, 4,... ou il peut s'agir d'un , b, c... après ":" est un format spécifiquement défini pour les types d'heure numériques (entier, virgule flottante). [] représente facultatif, | représente ou, un seul peut exister
3.1 L'identifiant du paramètre est avant ":"
// 只有参数id时候,: 可以省略不写
fmt::print("name:{1}, age: {0:}", 42, "knox");
3.2format_spec après ":" (Mini-langage de spécification de format de spécification de format)
-
Il s'agit
de format_spec ::= [[fill]align][sign][“#”][“0”][width][“.” précision][“L”][type]
fill ::= <un caractère autre que '{' ou '}'>
align ::= “<” | ">" | Signe « ^ »
::= « + » | «-» | " "
largeur ::= entier | "{" [arg_id] "}"
précision ::= entier | "{" [arg_id] "}"
tapez ::= "a" | « A » | « b » | «B» | « c » | «d» | «e» | «E» | « f » | «F» | « g » | «G» |
« o » | «p» | «s» | « x » | "X"\ -
file représente le caractère de remplissage, qui peut être n'importe quel point de code Unicode sauf "{" et "}". La présence d'un caractère de remplissage est indiquée par le caractère qui le suit, qui doit être une des options d'alignement. Si le deuxième caractère de format_spec n'est pas une option d'alignement valide (<, >, ^), ni les caractères de remplissage ni les options d'alignement ne sont supposés être présents.
-
align représente l'alignement, < représente l'alignement à gauche, > représente l'alignement à droite, ^ représente le centrage
-
le signe est uniquement pour les nombres, "+" signifie que les nombres positifs et négatifs utilisent des signes. "-" signifie que seuls les nombres négatifs nécessitent un signe (c'est le comportement par défaut). Un espace signifie qu'un espace doit être ajouté avant un nombre positif et un signe moins doit être ajouté avant un nombre négatif.
-
Cette option n'est disponible que pour les types entiers et à virgule flottante. Pour les entiers, lors de l'utilisation d'une sortie binaire, octale ou hexadécimale, cette option ajoute le préfixe approprié « 0b » (« 0B »), « 0 » ou « 0x » (« 0X ») à la valeur de sortie. Le format des caractères minuscules est en minuscules, comme {:#0X}, 255 = 0XFF, , {:#0x}, 255 = 0xff, les autres bases sont similaires,
-
width est un entier décimal, applicable uniquement aux types numériques, utilisé pour définir la largeur minimale du champ. Si elle n'est pas spécifiée, la largeur du champ sera déterminée par le contenu. Faire précéder le champ de largeur d'un caractère zéro (« 0 ») active le remplissage par zéro sensible au signe pour les types numériques.
Cela force le remplissage à être placé après le signe ou la base (le cas échéant) mais avant le numéro. Ceci permet d'imprimer le champ sous la forme "+000000120". -
"." La précision représente la précision. La précision n'existe que dans les types à virgule flottante. Les entiers, les caractères, les valeurs booléennes et les pointeurs ne sont pas autorisés à utiliser la précision. Pour les types non numériques, le champ indique la taille maximale du champ, même si la taille est spécifiée. Les chaînes C doivent se terminer par un caractère nul.
Le fichier précision.nf général, et non le fichier précision.nn, représente plusieurs formats qui doivent être formatés.
// 非数字指定的是输出的字符的个数。
fmt::print("name:{1}, age: {0:.5}", "1234567890", "knox");
// 输出:name:knox, age: 12345
// c字符串不够怎么办呢,最大字符串长
fmt::print("name:{1}, age: {0:.5}", "123", "knox");
// 输出:name:knox, age: 123
// 对于数字代表精度,只对浮点型有用
fmt::print("{:.2f}", 42.0f);
// 输出:42.00
//fmt::print("{:.2f}", 42); 编译报错
//fmt::print("{:.2f}", true); 编译报错
- L'option "L" utilise les paramètres régionaux actuels pour insérer les séparateurs numériques appropriés. Cette option n'est disponible que pour les types numériques.
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
fmt::print("{}", s);
// 输出: 1,234,567,890
- tapez
la notation exponentielle « e ». La notation d'index utilise la lettre minuscule « e ».
Notation d'index 'E'. La notation d'index utilise une lettre majuscule « E ».
Notation « f » à virgule fixe. Afficher les nombres sous forme de nombres à virgule fixe.
Notation à virgule fixe « F ». Afficher les nombres sous forme de nombres à virgule fixe. Identique à « f ».
'g' format général. En fonction de la taille du nombre et de la précision spécifiée, une notation à virgule fixe ou exponentielle est utilisée.
Format général 'G'. Identique à « g », mais utilise un « E » majuscule pour la notation d'index.
'x' entier hexadécimal. Afficher les nombres sous forme de nombres hexadécimaux.
'X' entier hexadécimal. Afficher les nombres sous forme de nombres hexadécimaux majuscules.
'un' nombre hexadécimal à virgule flottante. Utilisez le « a » minuscule pour la notation d’index.
'A' nombre hexadécimal à virgule flottante. Utilisez la lettre majuscule « A » pour la notation d'index.
Caractère « c ». Interprétez les entiers comme des caractères Unicode.
chaîne 's'. Formatez les paramètres sous forme de chaînes.
pointeur 'p'. Formater le pointeur sous forme de nombre hexadécimal.
chrono_format_spec formatage de l'heure
1. Composition
chrono_format_spec ::= [[fill]align][width][“.” précision][chrono_specs]
chrono_specs ::= [chrono_specs] conversion_spec | chrono_specs literal_char
conversion_spec ::= “%” [modifier] chrono_type
literal_char :: = <un caractère autre que '{', '}' ou '%'>\ // Sauf { } %, ces trois caractères peuvent être utilisés comme
modificateur de caractère de lien ::= “E” | “O”
chrono_type ::= " a" | "A" | "b" | "B" | "c" | "C" | "d" | "D" | "e" | "F" | "g" | "G" | "h
" | "H" | "I" | "j" | "m" | "M" | "n" | "p" | "q" | "Q" | "r" | "R" | "S" |
"t" | "T" | "u" | "U" | "V" | "
w" | "W" | "x" | "X" | "y" | "Y" | "z" | "Z " | "%"\
- [[fill]align] Similaire à 3.2.1
- Si le nombre de jours est inférieur à 10, le nombre de minutes, de secondes ou de mois sera ajouté avec 0 devant.
Pour une syntaxe plus détaillée de la chaîne de format fmt, veuillez vous rendre sur https://fmt.dev/latest/syntax .html#grammar-token-sf -identifier
Exemple de chaîne de formatage
Sortie dans l'ordre de arg_id, l'identifiant commence à 0
// 序号从零开始
fmt::print("{0}, {1}, {2}\n", 'a', 'b', 'c');
// print: "a, b, c"
fmt::print("{}, {}, {}\n", 'a', 'b', 'c');
// print: "a, b, c"
fmt::print("{2}, {1}, {0} \n", 'a', 'b', 'c');
// print: "c, b, a"
// fmt::print("{2}, {1}, {0} {3}\n", 'a', 'b', 'c'); 编译报错,没有第四个参数
// 输出
// a, b, c
// a, b, c
// c, b, a
Remplissez les espaces avec des caractères personnalisés et spécifiez la méthode de centrage
// 不指定填充符号默认为空格, 如果不存在 <>^ 就假定填充符号都不存在
fmt::print("{:<30}\n", "left aligned");
//
fmt::print("{:<<30}\n", "left aligned");
fmt::print("{:>30}\n", "right aligned");
fmt::print("{:>>30}\n", "right aligned");
fmt::print("{:^30}\n", "centered");
fmt::print("{:^^30}\n", "centered");
// 输出
//left aligned
//left aligned<<<<<<<<<<<<<<<<<<
// right aligned
//>>>>>>>>>>>>>>>>>right aligned
// centered
//^^^^^^^^^^^centered^^^^^^^^^^^
Définir dynamiquement la largeur et la précision
// 可以动态设置宽度和精度,但仅仅限制于此,
// 动态设置宽度的时候,宽度arg_id 为 参数+1,
// 0 1 2 3 参数arg_id 可以数{ 的个数,当然{} 一定是成对出现的。
fmt::print("{:<{}} {:.{}f} \n", "left aligned", 30, 3.14, 1);
fmt::print("{:.{}f}\n", 3.14, 1);
// 输出
// left aligned 3.1
// 3.1
Utilisation du signe :+ :-
// + 代表正数加+号,负数加-号
fmt::print("{:+f}; {:+f}\n", 3.14, -3.14);
// 空格正数加空格,负数加-号
fmt::print("{: f}; {: f}\n", 3.14, -3.14);
// -号代表正数不变,负数加-号 same as '{:f}; {:f}' 相当于是默认行为
fmt::print("{:-f}; {:-f}\n", 3.14, -3.14);
fmt::print("{:+}; {:+}\n", 3, -3);
fmt::print("{:-}; {:-}\n", 3, -3);
fmt::print("{: }; {: }\n", 3, -3);
fmt::print("{:}; {:}\n", 3, -3);
// 输出
//+3.140000; -3.140000
// 3.140000; -3.140000
//3.140000; -3.140000
//+3; -3
//3; -3
// 3; -3
//3; -3
sortie hexadécimale
// # 加上符号 0x 0 0b
fmt::print("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}\n", 42);
fmt::print("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}\n", 42);
// #06 代表宽度为6个, 不够的在进制之前使用0填充, 超出指定大小被忽略
fmt::print("int: {0:d}; hex: {0:#06x}; oct: {0:#06o}; bin: {0:#06b}\n", 42);
fmt::print("int: {0:d}; hex: {0:#01x}; oct: {0:#02o}; bin: {0:#03b}\n", 42);
// 输出
// int: 42; hex: 2a; oct: 52; bin: 101010
// int: 42; hex: 0x2a; oct: 052; bin: 0b101010
// int: 42; hex: 0x002a; oct: 000052; bin: 0b101010
// int: 42; hex: 0x2a; oct: 052; bin: 0b101010
Imprimer les bordures à l'aide de caractères de remplissage
fmt::print(
"┌{0:─^{2}}┐\n"
"│{1: ^{2}}│\n"
"└{0:─^{2}}┘\n", "", "Hello, knox!", 20);
Je ne peux plus résister, je m'arrête donc ici aujourd'hui et demain nous continuerons avec l'utilisation détaillée de l'API de la bibliothèque fmt.