programmez-en-d/sortie_formatee.whata

403 lines
17 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[set
title = "Sortie formatée"
partAs = chapitre
translator = "Raphaël Jakse"
proofreader = "Stéphane Goujet"
]
Ce chapitre traite des fonctionnalités du module [c std.format] de Phobos, et non des fonctionnalités du langage D lui-même. Les indicateurs de formatage d'entrée et de sortie du D sont similaires à ceux du C. Avant d'aller plus loin, je voudrais résumer ici les indicateurs de format et les drapeaux~ :
[ =. Drapeaux (peuvent être combinés)
[pre <<<
- aligner à gauche
+ afficher le signe
# afficher d'une autre manière
0 compléter avec des zéros
>>>
''espace''<<< compléter avec des espaces
>>>]
]
[ =. Indicateurs de format
[pre <<<
s par défaut
b binaire
d décimal
o octal
x,X hexadécimal
e,E écriture scientifique
f,F virgule flottante
g,G comme e ou f
a,A virgule flottante hexadécimal
>>>]
]
Nous avons utilisé des fonction comme [c writeln] avec de multiples paramètres si nécessaire. Les paramètres sont alors convertis vers leur représentation en chaîne de caractère et envoyés vers la sortie.
Parfois, ce n'est pas suffisant. La sortie peut devoir suivre un certain format. Jetons un œil sur le code suivant, utilisé pour afficher les éléments d'une facture~ :
[code=d <<<
éléments ~= 1.23;
éléments ~= 45.6;
for (int i = 0; i != éléments.length; ++i) {
writeln("Élément ", i + 1, " : ", éléments[i]);
}
>>>]
La sortie :
[output <<<
Élément 1 : 1.23
Élément 2 : 45.6
>>>]
L'information est correcte. Cependant, il est parfois souhaitable d'avoir un format de sortie différent. Par exemple, on pourrait vouloir qu'il y ait toujours deux chiffres après la virgule et que les points soient alignés, comme dans la sortie suivante~ :
[code=d <<<
Élément 1 : 1.23
Élément 2 : 45.60
>>>]
Dans de tels cas, la sortie formatée se révèle utile. Les fonctions de sortie que nous avons vues jusqu'à maintenant ont des équivalents contenant la lettre [c f], pour «~ formaté~ », dans leur nom~ : [c writef()] et [c writefln()]. Le premier paramètre de ces fonctions est une chaîne de formatage qui décrit comment les autres paramètres doivent être affichés.
Par exemple, la chaîne de formatage qui ferait afficher la sortie souhaitée ci-dessus à [c writefln()] est la suivante~ :
[code=d <<<
writefln("Élément %d : %9.02f", i + 1, éléments[i]);
>>>]
La chaîne de formatage contient des caractères normaux qui sont affichés tels quels, ainsi que des indicateurs de format spéciaux qui correspondent à chaque paramètre à afficher. Les indicateurs de format commencent par le caractère [c %] et finissent par un caractère de formatage. La chaîne de formatage ci-dessus contient deux indicateurs de format~ : [c %d] et [c %9.02f].
Chaque indicateur est associé aux paramètres qui suivent dans l'ordre. Par exemple, [c %d] est associé avec [c i+1] et [c %9.02f] est associé avec [c éléments~[i~]]. Chaque indicateur donne le format du paramètre auquel il correspond (les indicateurs de format peuvent également avoir des paramètres numériques[comment <<< "parameters numbers" : numéros de paramètres ? je me demande s'il ne veut pas parler de paramètres numérotés, positionnels ? >>>]~ ; nous verrons cela plus loin dans le chapitre).
Tous les autres caractères de la chaîne de format qui ne font pas partie d'un indicateur de format sont affichés tels quels. Ils correspondent aux caractères surlignés dans la chaîne suivante~ : [c "[mark Élément ]%d[mark :]%9.02f"].
Les indicateurs de format comportent 6 parties, la plupart desquelles sont optionnelles. La partie nommée ''position'' sera expliqué un peu plus tard. Les cinq autres parties sont les suivantes (note~ : les espaces entre ces parties sont insérés ici pour des raisons de lisibilité, ils ne font pas partie des indicateurs)~ :
[pre <<<
% drapeaux largeur précision caractère_de_formatage
>>>]
Le caractère [c %] au début et le caractère de formatage à la fin sont requis, les autres sont optionnels.
Du fait que [c %] a une signification spécifique dans les chaînes de formatage, quand un [c %] doit être affiché, il doit être écrit comme ceci~ : [c %%].
[ = Caractères de formatage
- [c b]~ : le paramètre entier est affiché dans le système binaire.
- [c o]~ : le paramètre entier est affiché dans le système octal.
- [c x] et [c X]~ : le paramètre entier est affiché dans le système hexadécimal~ ; avec des minuscules pour [c x] et des majuscules pour [c X].
- [c d]~ : le paramètre entier est affiché dans le système décimal~ ; un signe négatif est également affiché s'il s'agit d'un type signé et que la valeur est strictement négative.
[code=d <<<
int valeur = 12;
writefln("Binaire : %b", valeur);
writefln("Octal : %o", valeur);
writefln("Hexadécimal : %x", valeur);
writefln("Décimal : %d", valeur);
>>>]
[output <<<
Binaire : 1100
Octal : 14
Hexadécimal : c
Décimal : 12
>>>]
- [c e]~ : le paramètre flottant est affiché selon les règles suivantes~ :
- un seul chiffre avant le point~ ;
- un point si la précision n'est pas nulle~ ;
- des chiffres après le point, en nombre déterminé par la précision (6 par défaut)~ ;
- le caractère [c e] (signifiant «~ 10 puissance~ »)~ ;
- le signe [c +] ou [c -], selon si l'exposant est plus grand ou plus petit que zero~ ;
- l'exposant, constitué d'au moins deux chiffres.
- [c E]~ : pareil que [c e], sauf que le caractère [c E] est affiché à la place de [c e].
- [c f] et [c F]~ : le paramètre flottant est affiché dans le système décimal~ ; il y a au moins un chiffre avant le point et la précision par défaut est 6.
- [c g]~ : pareil que [c f] si l'exposant est entre -5 et ''précision''~ ; sinon pareil que [c e]. ''précision'' n'indique pas le nombre de chiffres après le point, mais les chiffres significatifs de la valeur complète [comment <<< «valeur entière», c'est source de confusion. >>>]. S'il n'y a pas de chiffres significatifs après le point, le point n'est pas affiché. Les zéros les plus à droite après le point ne sont pas affichés.
- [c G]~ : pareil que pour [c g] mais avec [c E] ou [c F].
- [c a]~ : le paramètre en virgule flottante est affiché dans le format flottant hexadécimal~ :
- les caractères [c 0x]~ ;
- un seul chiffre hexadécimal~ ;
- le point si la précision n'est pas nulle~ ;
- les chiffres après le point, dont le nombre est déterminé par la précision ; si la précision est indiquée, il y a autant de chiffres que nécessaire~ ;
- le caractère [c p] (signifiant «~ 2 puissance~ »)~ ;
- le caractère [c +] ou [c -] selon si l'exposant est plus grand ou plus petit que zéro~ ;
- l'exposant consistant en au moins un chiffre (l'exposant de la valeur 0 est 0).
- [c A]~ : pareil que [c a], mais avec [c 0X] et [c P].
[code=d <<<
double valeur = 123.456789;
writefln("avec e : %e", valeur);
writefln("avec f : %f", valeur);
writefln("avec g : %g", valeur);
writefln("avec a : %a", valeur);
>>>]
[output <<<
avec e : 1.234568e+02
avec f : 123.456789
avec g : 123.457
avec a : 0x1.edd3c07ee0b0bp+6
>>>]
- [c s]~ : la valeur est affichée de la même manière que dans une sortie non formatée, selon le type de paramètre~ :
- les valeurs booléennes comme [c true] ou [c false]~ ;
- les valeurs entières comme avec [c %d]~ ;
- les valeurs en virgule flottante comme avec [c %g]~ ;
- les chaînes codées en UTF-8~ ; la ''précision'' détermine le nombre maximal d'octets à utiliser (souvenez vous que dans le codage UTF-8, le nombre d'octets n'est pas le même que le nombre de caractères~ ; par exemple la chaîne [c "ağ"] a deux caractères, consistant en un total de trois octets)~ ;
- les structures et les classes comme le retour de la fonction [c toString()] de leur type~ ; la ''précision'' détermine le nombre maximal d'octets à utiliser~ ;
- les tableaux avec leurs éléments côte à côte.
[code=d <<<
bool b = true;
int i = 365;
double d = 9.87;
string s = "formatée";
auto o = File("fichier_test", "r");
int[] a = [ 2, 4, 6, 8 ];
writefln("booléen : %s", b);
writefln("entier : %s", i);
writefln("double : %s", d);
writefln("chaîne : %s", s);
writefln("objet : %s", o);
writefln("tableau : %s", a);
>>>]
[output <<<
booléen : true
entier : 365
double : 9.87
chaîne : formatée
objet : File(55738FA0)
tableau : [2, 4, 6, 8]
>>>]
]
[ = Largeur
Cette partie détermine la largeur du champ dans lequel le paramètre est affiché. Si la largeur est indiquée avec le caractère [c *], alors c'est le paramètre suivant qui indique cette largeur. Si la largeur est une valeur négative, le drapeau [c -] est implicite.
[code=d <<<
int valeur = 100;
writefln("Dans un champ de 10 caractères : %10s", valeur);
writefln("Dans un champ de 5 caractères : %5s", valeur);
>>>]
[output <<<
Dans un champ de 10 caractères : 100
Dans un champ de 5 caractères : 100
>>>]
]
[ = Précision
La précision est indiquée après le point dans l'indicateur de format. Pour les types en virgule flottante, elle détermine la précision de la représentation des valeurs. Si la précision est indiquée par le caractère [c *], la précision est obtenue à partir du paramètre suivant (ce paramètre doit être un [c int]). Les précisions négatives sont ignorées.
[code=d <<<
double valeur = 1234.56789;
writefln("%.8g", valeur);
writefln("%.3g", valeur);
writefln("%.8f", valeur);
writefln("%.3f", valeur);
>>>]
[output <<<
1234.5679
1.23e+03
1234.56789000
1234.568
>>>]
[code=d <<<
auto nombre = 0.123456789;
writefln("Nombre : %.*g", 4, nombre);
>>>]
[output <<<
Nombre : 0.1235
>>>]
]
[ = Drapeaux
On peut indiquer plus d'un drapeau à la fois.
- [c -]~ : la valeur est alignée à gauche dans son champ~ ; ce drapeau annule le drapeau [c 0]
[code=d <<<
int valeur = 123;
writefln("Normalement aligné à droite : |%10d|", valeur);
writefln("Aligné à gauche : |%-10d|", valeur);
>>>]
[output <<<
Normalement aligné à droite : | 123|
Aligné à gauche : |123 |
>>>]
- [c +]~ : si la valeur est positive, elle est préfixée par le caractère [c +]~ ; ce drapeau annule le drapeau espace.
[code=d <<<
writefln("Pas d'effet sur les valeurs négatives : %+d", -50);
writefln("Valeur positive avec le drapeau + : %+d", 50);
writefln("Valeur positive sans le drapeau + : %d", 50);
>>>]
[output <<<
Pas d'effet sur les valeurs négatives : -50
Valeur positive avec le drapeau + : +50
Valeur positive sans le drapeau + : 50
>>>]
- [c #]~ : affiche la valeur sous une autre forme, selon [c caractère_de_formatage].
- [c o]~ : le premier caractère de la valeur octale est toujours [c 0]~ ;
- [c x] et [c X]~ : si la valeur n'est pas zéro, elle est préfixée avec [c 0x] ou [c 0X]~ ;
- virgules flottantes~ : un point est affiché même s'il n'y a pas de chiffres significatifs après le point~ ;
- [c g] et [c G]~ : même les zéros non significatifs après le point sont affichés.
[code=d <<<
writefln("L'octal commence par un 0 : %#o", 1000);
writefln("L'hexadécimal commence par 0x : %#x", 1000);
writefln("Un point même si non nécessaire : %#g", 1f);
writefln("Les zéros à droite sont affichés : %#g", 1.2);
>>>]
[output <<<
L'octal commence par un 0 : 01750
L'hexadécimal commence par 0x : 0x3e8
Un point même si non nécessaire : 1.00000
Les zéros à droite sont affichés : 1.20000
>>>]
- [c 0]~ : le champ est complété avec des zéros (sauf si la valeur est [c nan] ou [c infinity])~ ; si la précision est également indiquée, ce drapeau est ignoré.
[code=d <<<
writefln("Dans un champ de 8 caractères : %08d", 42);
>>>]
[output <<<
Dans un champs de 8 caractères : 00000042
>>>]
- caractère espace~ : si la valeur est positive, un caractère espace est préfixé pour aligner les valeurs négatives et positives.
[code=d <<<
writefln("Pas d'effet sur les valeurs négatives : % d", -34);
writefln("Valeur positive avec un espace : % d", 56);
writefln("Valeur positive sans espace : %d", 56);
>>>]
[output <<<
Pas d'effet sur les valeurs négatives : -34
Valeur positive avec un espace : 56
Valeur positive sans espace : 56
>>>]
]
[ = Paramètres de position
Nous avons vu ci-dessus que les paramètres sont associés un à un avec les indicateurs dans la chaîne de formatage. Il est possible d'utiliser des numéros de position dans les indicateurs de format. Ceci permet d'associer des indicateurs avec des paramètres spécifiques. Les paramètres sont numérotés de façon croissante, en commençant par un 1. Les numéros de paramètres sont indiqués juste après le caractère [c %], suivi d'un [c $]~ :
[code <<<
% position$ drapeaux largeur précision caractère_de_formatage
>>>]
Un avantage des paramètres de positions est d'utiliser le même paramètre à plusieurs endroits dans la même chaîne de formatage~ :
[code=d <<<
writefln("%1$d %1$x %1$o %1$b", 42);
>>>]
La chaîne de formatage utilise le paramètre numéro 1 dans 4 indicateurs différents pour l'afficher en formats décimal, hexadécimal, octal et binaire~ :
[output <<<
42 2a 52 101010
>>>]
Une autre application de ces paramètres de position est de prendre en charge plusieurs langues. Lorsqu'ils sont référés par des numéros de position, les paramètres peuvent être déplacés n'importe où avec une chaînes de formatage spécifique à une langue. Par exemple, le nombre d'étudiants d'une classe peut être affichée de cette manière~ :
[code=d <<<
writefln("Il y a %s étudiants dans la classe %s.", nombre, classe);
>>>]
[output <<<
Il y a 20 étudiants dans la classe 1A.
>>>]
Supposons que le programme doive aussi prendre en charge le turc. La chaîne de formatage doit alors être choisie en fonction de la langue choisie. La méthode suivante utilise l'opérateur ternaire~ :
[code=d <<<
auto format = (langue == "fr"
 ? "Il y a %s étudiants dans la classe %s."
: "%s sınıfında %s öğrenci var.");
writefln(format, nombre, classe);
>>>]
Malheureusement, quand les paramètres sont associés un à un, la classe et le nombre d'étudiants sont inversés dans le message turc~ ; la classe s'affiche là où le nombre devrait être et inversement~ :
[output <<<
20 sınıfında 1A öğrenci var. ← Faux : signifie "classe 20", et "1A étudiants" !
>>>]
Pour éviter cela, les paramètres peuvent être indiqués par leur position pour associer chaque indicateur avec le bon paramètre~ :
[code=d <<<
auto format = (langue == "fr"
 ? "Il y a %s étudiants dans la classe %s."
: "%2$s sınıfında %1$s öğrenci var.");
writefln(format, nombre, classe);
>>>]
Maintenant, les paramètres apparaissent dans le bon ordre, indépendamment de la langue choisie :
[output <<<
Il y a 20 étudiants dans la pièce 1A.
1A sınıfında 20 öğrenci var.
>>>]
]
[ = [c format]
La sortie formatée est également utilisable avec la fonction [c format()] du module [c std.string]. [c format()] fonctionne de la même manière que [c writef()] mais retourne le résultat dans une chaîne au lieu de l'afficher~ :
[code=d <<<
import std.stdio;
import std.string;
void main()
{
write("Quel est ton nom ? ");
auto nom = chomp(readln());
auto resultat = format("Bonjour %s!", nom);
}
>>>]
Le programme pourra utiliser ce résultat plus tard.
]
[ = Exercices
# Écrire un programme qui lit une valeur et qui l'affiche dans le système hexadécimal.
# Écrire un programme qui lit une valeur flottante et qui l'affiche comme un pourcentage avec deux chiffres après le point. Par exemple, si la valeur est [c 1.2345], il devrait afficher [c 1.23%].
[[part:corrections/sortie_formatee || … Les solutions]]
]