IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

NumberFormat et séparateur de milliers [FAQ]


Sujet :

Java

  1. #1
    Membre confirmé Avatar de gronono
    Inscrit en
    Novembre 2003
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Novembre 2003
    Messages : 456
    Points : 482
    Points
    482
    Par défaut NumberFormat et séparateur de milliers
    Bonjour,

    J'ai rencontré un problème inattendu dans le test unitaire suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        @Test
        public void test() {
            NumberFormat nf = NumberFormat.getInstance();
            Assert.assertEquals("5 000", nf.format(5000));
        }
    Lorsqu'on lit le code précédent (et lorsqu'on l'écrit), on peut penser que le test passe sans problème.
    En réalité, il ne marche pas.

    Après une recherche approfondie, je me suis aperçu que NumberFormat utilise une espace insécable (code #160).

    Voici le code du test corrigé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
        @Test
        public void test() {
            char espace = new DecimalFormatSymbols().getGroupingSeparator();
            NumberFormat nf = NumberFormat.getInstance();
            Assert.assertEquals("5" + espace + "000", nf.format(5000));
        }
    Je pense qu'il serait utile de rajouter dans la réponse à la question Comment convertir un nombre en chaine formatée que le séparateur de milliers dans la langue française est l'espace insécable.

    A+
    Gronono

    EDIT : On dit une espace.

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    C'est vrai qu'il y a un gros problème avec les séparateurs de millier, mais je pense que ça va plus loin encore...

    Dans une application web + struts + struts-layout, j'avais utilisé le formateur DecimalFormat("#,###.00") ce qui donnait à l'affichage :
    pour 5000.5 -> 5 000,50

    Le problème, c'est qu'il n'y avait pas moyen de faire l'opération inverse (avec le même formateur) :
    pour 5 000,50 -> 5 ???

    Finalement, j'ai du retirer les séparateurs de millier pour que ça fonctionne, dommage...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre confirmé Avatar de gronono
    Inscrit en
    Novembre 2003
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Novembre 2003
    Messages : 456
    Points : 482
    Points
    482
    Par défaut
    En fait, si on sait que c'est une espace insécable, il n'y plus de problème. Le deuxième test le prouve :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    @Test
        public void test() {
            char espace = new DecimalFormatSymbols().getGroupingSeparator();
            NumberFormat nf = NumberFormat.getInstance();
            Assert.assertEquals("5" + espace + "000", nf.format(5000));
     
            try {
                Assert.assertEquals(5000, nf.parse("5" +espace+ "000"));
            } catch (ParseException e) {
                e.printStackTrace();
                fail();
            }
     
            try {
                Assert.assertEquals(5, nf.parse("5 000"));
            } catch (ParseException e) {
                e.printStackTrace();
                fail();
            }
        }
    C'est vrai que le dernier test est bizarre. J'aurais plutôt vu une ParseException. Mais bon, c'est pas moi qui fait l'API.

    C'est pour ces raisons qu'il faut que FAQ soit mise à jour. Le comportement que l'on attend n'est pas celui que l'on obtient (dut moins pour nous deux).

    A+
    Gronono.

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    Juste pour info, en typographie, espace est féminin => une espace insécable. Pareil pour tout en typographie : Pour aérer le texte, ajoute une espace.

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dingoth Voir le message
    Juste pour info, en typographie, espace est féminin => une espace insécable. Pareil pour tout en typographie : Pour aérer le texte, ajoute une espace.
    Super, on prend même des cours de français ici

    Ceci dit, ça ne fait pas vraiment avancer le problème de conversion avec blanc séparateur de millier...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Ceci dit, ça ne fait pas vraiment avancer le problème de conversion avec blanc séparateur de millier...
    Le problème étant qu'il y a deux caractères bien différents : l'espace (\u0020) et l'espace insécable (\u00a0).

    Si tu parses des chaines provenant d'une saisie humaine il y a de forte chance que la chaine ne comporte pas d'espace insécable.

    Tu as alors deux solutions :



    Citation Envoyé par OButterlin Voir le message
    Le problème, c'est qu'il n'y avait pas moyen de faire l'opération inverse (avec le même formateur) :
    pour 5 000,50 -> 5 ???
    Ce problème vient d'une particularité des NumberFormat qui se contente du premier chiffre trouvé sans forcément lire toutes la chaine : le parse s'arrête au premier caractère incorrect ! Donc dans ton cas l'espace 'simple' est un caractère incorrect ce qui fait que le parse se contente du "5"...

    Pour éviter cela il faut utiliser parse(String,ParsePosition) et vérifier les index, par exemple cette méthode parsera la totalité de la chaine qu'elle reçoit en paramètre, ou renverra une exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    	public static Number parseFull(NumberFormat nf, String source) throws ParseException {
    		ParsePosition parsePosition = new ParsePosition(0);
    		Number number = nf.parse(source, parsePosition);
    		// On vérifie qu'il n'y ai pas d'erreur :
    		if (parsePosition.getErrorIndex() >= 0) {
                throw new ParseException("Unparseable number: \"" + source + "\"",
                                         parsePosition.getErrorIndex());
            }
    		// On vérifie que toute la chaine a bien été parsé :
    		if (parsePosition.getIndex() != source.length()) {
                throw new ParseException("Unparseable number: \"" + source + "\"",
                        parsePosition.getIndex());
    		}
    		return number;
    	}

    a++

  7. #7
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    et bien pour une explication complète... merci à toi

    C'est tout de même dommage qu'il ne traite pas les blancs simples lui même, le fait d'utiliser le blanc insécable étant certainement lié au problème de césure des navigateurs sur blanc (\u0020)...

    Du coup, je vais peut-être me faire une classe utilitaire étendant DecimalFormat pour redéfinir la méthode parse et convertir les \u0020 en \u00A0
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre confirmé Avatar de gronono
    Inscrit en
    Novembre 2003
    Messages
    456
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Novembre 2003
    Messages : 456
    Points : 482
    Points
    482
    Par défaut
    Citation Envoyé par dingoth Voir le message
    Juste pour info, en typographie, espace est féminin => une espace insécable. Pareil pour tout en typographie : Pour aérer le texte, ajoute une espace.
    Effectivement. C'est corrigé.

    Citation Envoyé par adiGuba
    Ce problème vient d'une particularité des NumberFormat qui se contente du premier chiffre trouvé sans forcément lire toutes la chaine : le parse s'arrête au premier caractère incorrect ! Donc dans ton cas l'espace 'simple' est un caractère incorrect ce qui fait que le parse se contente du "5"...
    Merci adiGuba pour cette précision.

    A+
    Gronono

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Séparateur de millier
    Par fo comlan dans le forum Général Python
    Réponses: 6
    Dernier message: 20/06/2007, 14h17
  2. [SQL] séparateur de millier
    Par moneyinthebank dans le forum Langage SQL
    Réponses: 4
    Dernier message: 19/10/2006, 11h36
  3. Séparateurs des milliers
    Par blowlagoon dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 26/05/2006, 10h02
  4. Format des nombres entiers, séparateurs de milliers
    Par zazaraignée dans le forum Langage
    Réponses: 2
    Dernier message: 26/10/2005, 01h25
  5. [VB.NET] Séparateur de milliers
    Par anael dans le forum Windows Forms
    Réponses: 4
    Dernier message: 24/03/2005, 15h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo