Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Formatage de chaînes de caractères

StringBuilder / StringBuffer Utilisation de tableaux



Accès rapide :
La vidéo
Le principe de formatage
Exemple d'utilisation de la méthode System.out.printf
Exemple d'utilisation de la méthode String.format
Formatage de données entières
Comment contrôler la base numérique à utiliser pour le formatage ?
Comment contrôler le nombre de caractères utilisé dans le formatage ?
Formater un entier en groupes de chiffres, pour une localisation donnée
Formatage de données flottantes
Formatage simple de vos flottants
Formatage de vos flottants en utilisant des informations de localisation
Formatage de caractères et de chaînes de caractères
Autres types pouvant être injectés
Un petit exemple concret d'utilisation

La vidéo

Cette vidéo vous montre comment produire des chaînes de caractères formatées via les méthodes String.format et System.out.printf. Un certain nombre de spécificités, pour chaque type de données à formater, vous est proposé. Un exemple concret d'utilisation, vous est aussi proposé en fin de cette vidéo (une mini commande ls codée en Java).


Formatage de chaînes de caractères

Le principe de formatage

Imaginons que nous ayons deux valeurs entières représentant les deux parties d'un nombre rationnel (une fraction) : le numérateur et le dénominateur. Comment afficher ces deux informations ? La première solution pourrait être de faire des concaténations de bouts de chaînes de caractères.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
public class Demo {
            
    public static void main(String[] args) {

        int num = 25;
        int den = 11;
        System.out.println( "[" + num + "/" + den + "]" );
        
    }
    
}
Quelques concaténations
comme nous l'avons vu en fin de chapitre précédent, il n'est pas nécessaire, dans cet exemple, d'utiliser la classe java.lang.StringBuilder. Le compilateur se charge de transformer le code à notre place.

Exemple d'utilisation de la méthode System.out.printf

Mais nous aurions pu utiliser une autre technique pour arriver au même résultat : produire une chaine formatée. Vous avez au moins deux façons de formater une chaîne de caractères : soit vous utilisez la methode System.out.printf, soit String.format. La première solution envoie directement le résultat sur la console, alors que la seconde technique permet de récupérer un objet de type String. Voici un exemple utilisant System.out.printf.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
public class Demo {
            
    public static void main(String[] args) {

        int num = 25;
        int den = 11;
        System.out.printf( "[%d/%d]\n", num, den );
        
    }
    
}
Utilisation de la méthode System.out.printf
comme vous l'aurez noté, outre le formatage, il existe une différence entre la méthode println et printf : la première force un retour à la ligne (d'où le ln pour line) alors que la seconde méthode n'en n'impose pas. Pour autant, si vous souhaitez un retour à la ligne finissez votre chaîne par un caractère \n.

Comment fonctionne le formatage ? Le premier paramètre de la méthode printf correspond au format : "[%d/%d]\n". Ce qui est important d'y repérer, ce sont les deux %d : ils indiquent qu'on cherche à injecter en lieu et place de ces deux séquences de caractères des entiers exprimés en base numérique décimale (c'est ce qu'indique le caractère d). Comme il y a deux % dans le format, on trouve à la suite du format deux paramètres entiers : le numérateur et le dénominateur.

Comme nous allons le voir dans la suite de ce document, le formalisme utilisé, pour indiquer les zones à remplacer dans le format, est relativement complexe et on peut y exprimer beaucoup de choses.

Exemple d'utilisation de la méthode String.format

Ce nouvel exemple montre l'autre possibilité, à savoir l'invocation de la méthode String.format. La signification des paramètres est identique à System.out.printf. La vraie différence étant que String.format renvoie la chaîne de caractères après formatage.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
public class Demo {
            
    public static void main(String[] args) {

        int num = 25;
        int den = 11;
        String str = String.format( "[%d/%d]", num, den );
        System.out.println( str );
        
    }
    
}
Utilisation de la méthode String.format
dans cet exemple, le retour à la ligne a été retiré du format, afin de laisser la méthode System.out.println le produire.

Formatage de données entières

Comment contrôler la base numérique à utiliser pour le formatage ?

Vous pouvez contrôler la base numérique à utiliser pour le formatage de vos entiers. Voici la liste des bases numériques supportées lors du formatage.

Séquence Signification
%d Permet de formater un entier en base décimale.
%o Permet de formater un entier en base octale.
%x Permet de formater un entier en base hexadécimale.

Voici un petit exemple d'utilisation.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
public class Demo {
            
    public static void main(String[] args) {

        int value1 = 10;
        int value2 = 128;
        int value3 = 255;
        
        System.out.printf( "octal - %o - %o - %o\n", value1, value2, value3 );
        System.out.printf( "decimal - %d - %d - %d\n", value1, value2, value3 );
        System.out.printf( "hexadecimal - %x - %x - %x\n", value1, value2, value3 );
        
        // Cas du binaire, non directement supporté
        System.out.printf( "binary - %s\n", Integer.toBinaryString( value3 ) );

    }
    
}
Utilisation de la méthode String.format
si vous souhaiter souhaitez obtenir la représentation binaire d'une valeur entière, utilisez la méthode Integer.toBinaryString( value ), qui renvoie une chaîne de caractères. Le %s correspond donc à une injection d'une donnée de type String.

Voici les résultats produits par le programme précédent.

octal - 12 - 200 - 377
decimal - 10 - 128 - 255
hexadecimal - a - 80 - ff
binary - 11111111

Comment contrôler le nombre de caractères utilisé dans le formatage ?

Le formalisme vous permet de contrôler le nombre de caractères utilisé pour le formatage d'un entier. Le tableau ci-dessous vous montre quelques possibilités

Séquence Signification
%3d Permet de formater un entier en base décimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%-3d Permet de formater un entier en base décimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à droite. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%03d Permet de formater un entier en base décimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des 0 seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%3o Permet de formater un entier en base octale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%-3o Permet de formater un entier en base octale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à droite. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%03o Permet de formater un entier en base octale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des 0 seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%3x Permet de formater un entier en base hexadécimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%-3x Permet de formater un entier en base hexadécimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des blancs seront insérés à droite. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.
%03x Permet de formater un entier en base hexadécimale en utilisant au minimum 3 caractères. Si la valeur est plus petite que le nombre de chiffres demandé, des 0 seront insérés à gauche. Si la valeur de l'entier dépasse cette taille, bien entendu, aucun chiffre ne sera perdu et tant pis pour la taille.

Voici un petit exemple d'utilisation de ces formats. Cette fois ci, on cherche à utiliser un minimum de cinq caractères pour chaque formatage.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
public class Demo {
            
    public static void main(String[] args) {

        int value = 10;

        System.out.printf( "<%5o> <%-5o> <%05o>\n", value, value, value );
        System.out.printf( "<%5d> <%-5d> <%05d>\n", value, value, value );
        System.out.printf( "<%5x> <%-5x> <%05x>\n", value, value, value );

        System.out.printf( "<%5d>\n", 1_000_000 );
        
    }
    
}
Contrôle de la taille et de l'alignement d'un format

Et voici les résultats produits par ce programme.

<   12> <12   > <00012>
<   10> <10   > <00010>
<    a> <a    > <0000a>
<1000000>

Formater un entier en groupes de chiffres, pour une localisation donnée

Il est possible de formater vos entiers en groupant les chiffres par paquets (classiquement 3 chiffres par paquet). Mais un problème se pose alors : selon la localisation considérée, le caractère de séparation de groupes est différent. Il faut donc spécifier la localisation à utiliser. A défaut, c'est la configuration de votre système d'exploitation qui sera considérée.

En Java, une localisation se définie en utilisant la classe java.util.Locale. Comme cette classe n'est pas dans le paquetage java.lang, un import sera obligatoire en tête de votre fichier de code. Le code suivant vous montre comment définir un objet de localisation en spécifiant un code langue (sur 2 caractères en minuscules) et un code pays (aussi sur deux caractères en majuscules).

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
import java.util.Locale;
            
public class Demo {
            
    public static void main(String[] args) {

        Locale frenchLocale = new Locale( "fr", "FR" );
        System.out.println( frenchLocale );                 // Affiche fr_FR
        
        Locale usLocale = new Locale( "en", "US" );
        System.out.println( usLocale );                     // Affiche en_US

        Locale defaultLocale = Locale.getDefault();
        System.out.println( defaultLocale );                // Affiche la localisation du système
        
    }
    
}
Quelques exemples d'utilisation de la classe java.util.Locale
il n'est pas obligatoire de fournir le code pays. On peut donc imaginer un simple new Locale( "fr" ). Mais n'oubliez pas qu'il existe des différences non négigeables entre les français utilisé en France et celui utilisé au Canada, d'ou l'importance de spécifier le code pays.

Pour activer le groupage, il faut glisser un caractère , juste après le caractère %. Le groupage n'est accepté que pour la représentation décimale (donc pas pour l'hexadécimal ou l'octal). Voici quelques exemples d'utilisation du groupage de chiffres.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
import java.util.Locale;
            
public class Demo {
            
    public static void main(String[] args) {

        int price = 1_234_567_890;
        System.out.printf( "%,d\n", price );
        System.out.printf( new Locale( "fr", "FR"), "%,d\n", price );   
        System.out.printf( new Locale( "en", "US"), "%,d\n", price );   
        System.out.printf( new Locale( "it", "IT"), "%,d\n", price );   
        
    }
    
}
Quelques exemples de groupage de chiffres

Et voici les résultats produits par cet exemple de code.

$> javac Demo.java
$> java Demo
1 234 567 890
1 234 567 890
1,234,567,890
1.234.567.890
$>

Formatage de données flottantes

Formatage simple de vos flottants

Tout comme vous pouvez formater vos valeurs entières, il est possible de formater vos valeurs flottantes. Pour introduire un flottant dans un format, il faut utiliser le marqueur %f (pour float). Entre ces ceux caractères, il est possible de spécifier certaines informations de formatage. Le tableau suivant en présente quelques exemples.

Séquence Signification
%f Permet d'injecter un flottant (en base décimale).
%.2f Permet d'injecter un flottant en limitant la partie flottante à deux chiffres après la virgule (arrondi au plus proche).
%5.2f Permet d'injecter un flottant en le formatant sur 5 caractères au total (point compris) et en limitant la partie flottante à deux chiffres après la virgule (arrondi au plus proche). Il reste donc deux caractères pour la partie entière. Si la partie entière tient sur un seul caractère, un blanc sera ajouté à gauche. Si la partie flottante tient sur un seul caractère, un caractère 0 sera ajouté à droite. Si la valeur de de la partie entière fait dépasser cette taille alors le format ne pourra être respecté.
%05.2f Permet d'injecter un flottant en le formatant sur 5 caractères au total (point compris) et en limitant la partie flottante à deux chiffres après la virgule (arrondi au plus proche). Il reste donc deux caractères pour la partie entière. Si la partie entière tient sur un seul caractère, un caractère 0 sera ajouté à gauche. Si la partie flottante tient sur un seul caractère, un caractère 0 sera ajouté à droite. Si la valeur de de la partie entière fait dépasser cette taille alors le format ne pourra être respecté.
%e Permet de formater un flottant en utilisant une représentation exponentielle (mantisse et exposant).

Le programme suivant vous propose quelques exemples de formats utilisables sur vos données flottantes.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
public class Demo {
            
    public static void main(String[] args) {

        // Notation traditionnelle
        System.out.printf( "1 - %f\n", Math.PI );       
        System.out.printf( "2 - %.2f\n", Math.PI );     
        System.out.printf( "3 - %5.2f\n", Math.PI );        
        System.out.printf( "4 - %05.2f\n", Math.PI );       
        System.out.printf( "5 - %5.2f\n", 100+Math.PI );    // Dépassement du format
    
        // Notation exponentielle
        System.out.printf( "6 - %e\n", Math.PI );   
        
    }
    
}
Formatage de données flottantes

Et voici les résultats produits par l'exemple ci-dessus.

1 - 3,141593
2 - 3,14
3 -  3,14
4 - 03,14
5 - 103,14
6 - 3,141593e+00

Formatage de vos flottants en utilisant des informations de localisation

Il est possible de formater vos flottants en contrôlant le caractère de groupage de digit et celui de séparation de la partie décimale en utilisant les informations de localisation de la JVM. Tout comme je vous l'ai montré pour le formatage de vos entiers, il faudra utiliser la classe java.util.Locale pour spécifier la localisation à utiliser.

Pour demander le groupage de vos chiffres, il faut rajouter le caractère , juste après le %. Voici un petit exemple d'utilisation de cette possibilité.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
import java.util.Locale;

public class Demo {
            
    public static void main(String[] args) {

        double price = 1_000_000.123456789;

        System.out.printf( "default - %,f\n", price );      // Use Locale.getDeault();
        System.out.printf( new Locale( "fr", "FR"), "fr - %,f\n", price );  
        System.out.printf( new Locale( "en", "US"), "en - %,f\n", price );  
        System.out.printf( new Locale( "it", "IT"), "it - %,f\n", price );  
        
        System.out.printf( "1 - %,.2f\n", price );
        System.out.printf( "2 - %,12.2f\n", price );
        System.out.printf( "3 - %,13.2f\n", price );
        System.out.printf( "4 - %,013.2f\n", price );
        System.out.printf( "5 - %013.2f\n", price );
        
    }
    
}
Formatage de données flottantes en fonction de la localisation
les derniers formats (lignes 15 à 17) doivent tenir compte, dans le calcul de la taille totale du format (ici 13 caractères), des caractères de séparation de groupes.

Et voici les résultats produits par l'exemple ci-dessus.

default - 1 000 000,123457
fr - 1 000 000,123457
en - 1,000,000.123457
it - 1.000.000,123457
1 - 1 000 000,12
2 - 1 000 000,12
3 -  1 000 000,12
4 - 01 000 000,12
5 - 0001000000,12

Formatage de caractères et de chaînes de caractères

Vous pouvez aussi injecter dans votre format des données de type char (%c) ou de type String (%s). Le tableau suivant présente quelques formats possibles (notamment pour vos chaînes de caractères).

Séquence Signification
%c Permet d'injecter un caractère.
%% Permet d'injecter le caractère %. Cela est nécessaire étant donné que ce caractère à une signification particulière dans votre format.
%s Permet d'injecter une chaîne de caractères.
%10s Permet d'injecter une chaîne de caractères en utilisant 10 caractères dans l'affichage. La chaîne de caractères injectée sera alignée par la droite. Si la taille de la chaîne est plus petite que la taille spécifiée, des blancs seront ajoutés à la gauche de la chaîne. Si la taille de la chaîne est plus grande que la taille spécifiée, l'information de taille du format sera ignorée.
%-10s Permet d'injecter une chaîne de caractères en utilisant 10 caractères dans l'affichage. La chaîne de caractères injectée sera alignée par la gauche. Si la taille de la chaîne est plus petite que la taille spécifiée, des blancs seront ajoutés à la droite de la chaîne. Si la taille de la chaîne est plus grande que la taille spécifiée, l'information de taille du format sera ignorée.

Voici un petit exemple d'utilisation de ces formats.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
import java.util.Date;

public class Demo {
            
    public static void main(String[] args) {

        System.out.printf( "%c - %% - %s\n", 'z', "zorro" );
        System.out.printf( ">%10s<\n", "toto" );
        System.out.printf( ">%-10s<\n", "toto" );
    
    }
    
}
Formatage de chaînes de caractères

Et voici les résultats produits par l'exemple ci-dessus.

z - % - zorro
>      toto<
>toto      <

Autres types pouvant être injectés

Le tableau ci-dessous complète nos connaissances avec quelques formatage de types supplémentaires et notamment les booléens et les dates.

Séquence Signification
%b Permet d'injecter un booléen.
%tF Permet d'injecter une date au format yyyy-mm-dd.
%tT Permet d'injecter un temps au format hh:mm:ss.
%h Permet d'injecter la chaîne de caractère représentant le hashcode d'une instance (d'un objet) Java. Cette notion de hashcode est principalement utilisée par les tables associatives exploitant l'algorithme de hashcoding (adressage dispersé). Le hashcode s'obtient en invoquant la méthode hashCode sur une instance Java et la plus part du temps cette méthode est définie de manière à renvoyer l'adresse mémoire de l'objet (mais ça peut ne pas être le cas).
il existe plusieurs autres possibilités de formatage pour vos dates. Pour de plus amples informations, je vous renvoie vers la Javadoc.

Voici un petit exemple d'utilisation de ces formats.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
import java.util.Date;

public class Demo {
            
    public static void main(String[] args) {

        // Injection d'un booléen
        System.out.printf( "%b \n", true );

        // Injection d'une date et d'un temps
        Date now = new Date();
        System.out.printf( "%tF %tT\n", now, now );
        // Idem avec une seule instance : %<tT
        // Le caractère < demande à réutilisé l'instance de date précédemment utilisée.
        System.out.printf( "%tF %<tT\n", now );
    
        // Trois syntaxes équivalentes pour afficher le hashcode d'un objet Java
        // Sauf cas particuliers, le hashcode correspond à l'adresse mémoire de l'instance.
        Date javaObject = new Date(); 
        System.out.printf( "%h \n", javaObject );       
        System.out.printf( "%x \n", javaObject.hashCode() );
        System.out.println( Integer.toHexString( javaObject.hashCode() ) );
        
    }
    
}
Autres possibilités de formatages

Et voici les résultats produits par l'exemple ci-dessus.

true 
2018-01-29 11:23:40
2018-01-29 11:23:40
415dc557 
415dc557 
415dc557

Un petit exemple concret d'utilisation

Afin de vous proposer un exemple un peu plus concret, nous allons essayer d'afficher le contenu d'un dossier d'une manière un peu similaire à la commande ls -l (sur un système d'exploitation Unix/Linux) ou dir (sous système Windows). Voici le code de notre exemple.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
import java.util.Date;

public class Listing {
            
    public static void main(String[] args) {

        // Soit on liste le contenu du répertoire courant (.)
        // Soit on utilise le chemin passé en paramètre sur args[0]
        String path = ".";
        if ( args.length == 1 ) {
            path = args[0]; 
        }
    
        // On affiche un header
        System.out.println( "+------+------------+---------------------+----------------------+" );
        System.out.println( "| Type | Size       | Date       Time     | File name            |" );
        System.out.println( "+------+------------+---------------------+----------------------+" );
        
        // On traite et affiche chaque entrée du dossier considéré
        File [] files = new File( path ).listFiles();
        for( File file  : files ) {
            char type = file.isDirectory() ? 'd' : '-';
            long sizeKo = file.length() / 1024;
            Date lastModified = new Date( file.lastModified() );
            String name = file.getName();
            
            System.out.printf( "| %c    | %,10d | %tF %tT | %-20s |\n", 
                               type, sizeKo, lastModified, lastModified, name );
        }
        // On affiche un footer
        System.out.println( "+------+------------+---------------------+----------------------+" );
    
    }
    
}
Listing d'un dossier avec affichages formatés

Et voici les résultats produits par l'exemple ci-dessus.

+------+------------+---------------------+----------------------+
| Type | Size (Ko)  | Date       Time     | File name            |
+------+------------+---------------------+----------------------+
| d    |      4 096 | 2018-01-26 10:33:29 | src                  |
| d    |      4 096 | 2017-03-14 14:27:11 | .settings            |
| -    |        295 | 2017-03-14 14:27:11 | .classpath           |
| d    |      4 096 | 2018-01-23 11:26:45 | bin                  |
| -    |        375 | 2017-03-14 14:27:11 | .project             |
+------+------------+---------------------+----------------------+

Pour conclure ce chapitre, notez bien que ne n'ai pas été exhaustif dans la liste des possibilités de formatages. Si vous souhaitez allez plus loin dans l'étude de ces possibilités, je vous renvoie vers la page de la Javadoc associée.



StringBuilder / StringBuffer Utilisation de tableaux