Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 8 sur 8
  1. #1
    Membre éclairé Avatar de gronono
    Inscrit en
    novembre 2003
    Messages
    452
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : novembre 2003
    Messages : 452
    Points : 396
    Points
    396

    Par défaut NumberFormat et séparateur de milliers

    Bonjour,

    J'ai rencontré un problème inattendu dans le test unitaire suivant :
    Code :
    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 :
    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
    5 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 5 612
    Points : 6 241
    Points
    6 241

    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...

  3. #3
    Membre éclairé Avatar de gronono
    Inscrit en
    novembre 2003
    Messages
    452
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : novembre 2003
    Messages : 452
    Points : 396
    Points
    396

    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 :
    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 Expert
    Profil pro
    Inscrit en
    mai 2004
    Messages
    1 254
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : mai 2004
    Messages : 1 254
    Points : 1 240
    Points
    1 240

    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
    5 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 5 612
    Points : 6 241
    Points
    6 241

    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...

  6. #6
    Expert Confirmé Sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    avril 2002
    Messages
    13 272
    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 272
    Points : 19 342
    Points
    19 342

    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 :
    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
    5 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : novembre 2006
    Messages : 5 612
    Points : 6 241
    Points
    6 241

    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

  8. #8
    Membre éclairé Avatar de gronono
    Inscrit en
    novembre 2003
    Messages
    452
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations forums :
    Inscription : novembre 2003
    Messages : 452
    Points : 396
    Points
    396

    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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •