Précédent   Forum du club des développeurs et IT Pro > Java > Communauté Java > Contribuez
Contribuez Proposez vos articles, cours, tutoriels, FAQ, sources, et autres ressources pour la rubrique Java.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 05/03/2008, 01h08   #1
gronono
Membre éprouvé
 
Avatar de gronono
 
Inscription : novembre 2003
Messages : 452
Détails du profil
Informations personnelles :
Âge : 31

Informations forums :
Inscription : novembre 2003
Messages : 452
Points : 408
Points : 408
Envoyer un message via MSN à gronono
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.
gronono est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 11h01   #2
OButterlin
Modérateur
 
Avatar de OButterlin
 
Homme
Inscription : novembre 2006
Messages : 5 087
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : novembre 2006
Messages : 5 087
Points : 5 821
Points : 5 821
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...
OButterlin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 11h14   #3
gronono
Membre éprouvé
 
Avatar de gronono
 
Inscription : novembre 2003
Messages : 452
Détails du profil
Informations personnelles :
Âge : 31

Informations forums :
Inscription : novembre 2003
Messages : 452
Points : 408
Points : 408
Envoyer un message via MSN à gronono
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.
gronono est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 13h46   #4
dingoth
Membre Expert
 
Inscription : mai 2004
Messages : 1 253
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : mai 2004
Messages : 1 253
Points : 1 298
Points : 1 298
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.
dingoth est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 14h48   #5
OButterlin
Modérateur
 
Avatar de OButterlin
 
Homme
Inscription : novembre 2006
Messages : 5 087
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : novembre 2006
Messages : 5 087
Points : 5 821
Points : 5 821
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...
OButterlin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 15h14   #6
adiGuba
Expert Confirmé Sénior
 
Avatar de adiGuba
 
Homme
Développeur Java/Web
Inscription : avril 2002
Messages : 12 654
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Corse (Corse)

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

Informations forums :
Inscription : avril 2002
Messages : 12 654
Points : 22 428
Points : 22 428
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++
__________________
adiGuba [ tutoriels | blog | twitter ] Rédacteur/Modérateur Java Présentation de Java SE 7 (commentaires)
adiGuba est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 15h52   #7
OButterlin
Modérateur
 
Avatar de OButterlin
 
Homme
Inscription : novembre 2006
Messages : 5 087
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : novembre 2006
Messages : 5 087
Points : 5 821
Points : 5 821
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
OButterlin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/03/2008, 20h47   #8
gronono
Membre éprouvé
 
Avatar de gronono
 
Inscription : novembre 2003
Messages : 452
Détails du profil
Informations personnelles :
Âge : 31

Informations forums :
Inscription : novembre 2003
Messages : 452
Points : 408
Points : 408
Envoyer un message via MSN à gronono
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
gronono est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 10h48.


 
 
 
 
Partenaires

Hébergement Web