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

Collection et Stream Java Discussion :

[Internationalisation] Une chaîne renvoyée par ResourceBundle a un espace encodé d'une manière gênante


Sujet :

Collection et Stream Java

  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    605
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 605
    Points : 670
    Points
    670
    Par défaut [Internationalisation] Une chaîne renvoyée par ResourceBundle a un espace encodé d'une manière gênante
    Bonjour,

    Je suis entrain de mettre au point des tests unitaires pour valider quelques fonctions de gestion de l'internationalisation.
    L'un d'entre-eux a stoppé sur un problème inattendu.

    La méthode toString() d'un objet internationalisé que j'ai renvoie une String en l'ayant constituée depuis un ResourceBundle où une propriété "toString='{'valeur : {0,number}'}', {1}" se trouve pour le français et "toString='{'value : {0,number}'}', {1}" pour l'anglais.
    Je n'entre pas dans le détail de l'objet qui est un objet de test, mais sa méthode toString() répond dans mon cas de test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    {valeur : 4 500}, locales : [fr_FR, en_GB], id : A, anomalies : anomalies : [
    Anomalie ce 09/03/14. (ERREUR, -2121367804, fr)
    ]
    Ce que je veux faire dans mon test, c'est vérifier que lorsque c'est le français qui aura du être retenu je trouverai dedans la chaîne "4 500", et que quand ce sera l'anglais, ce sera "4,500". le séparateur de milliers différant.
    alors, j'ai écrit un simple test se résumant à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assertTrue(o.toString().indexOf("4 500") != -1);
    Mais ce test échoue. Et cela, alors même que visuellement je vois bien que dans son toString(), cette valeur, il la porte bien.

    J'ai cherché et suis devenu embarrassé en constatant ceci :
    Le "4 500" qui est dans l'indexOf de mon test est représenté sous forme d'octets ainsi : [52, 32, 53, 48, 48],
    mais celui qui se trouve dans la chaîne de caractères renvoyée par le toString() de mon objet l'est de cette manière : [52, -62, -96, 53, 48, 48] pour la séquence qui m'intéresse.

    L'espace est codé [32] dans l'une, [-62, -96] dans l'autre, et s'ils ont visuellement le même aspect, c'est que c'est sans doute un choix d'encodage.
    Qui m'ennuie... car je n'ai pas encore pris l'initiative de toucher aux encodages sachant à quels affres cela peut mener si l'on y est pas bien préparé. Alors, ce que j'observe m'intrigue.

    J'espère qu'avec un Collator.compare() je vais pouvoir me sortir d'affaire, mais je ne suis pas serein parce que je ne comprends pas bien comment un simple couple d'appels ResourceBundle + MessageFormat a pu amener à un changement d'encodage d'espace.

    Avez-vous une idée de pourquoi ? Mon PC est tout ce qu'il faut fr_FR...

    Merci !

  2. #2
    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
    Salut,


    C'est normal : le formatage des nombres en français n'utilise pas l'espace "simple", mais un espace insécable.
    Cela permet d'éviter que le nombre soit tronqué sur deux lignes s'il est placé dans un texte par exemple...

    Tu peux utiliser la forme unicode \u00a0 pour utiliser cet espace dans le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assertTrue(o.toString().indexOf("4\u00a0500") != -1);
    a++

  3. #3
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    605
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 605
    Points : 670
    Points
    670
    Par défaut
    Oh je te remercie beaucoup ! Ça c'est de l'aide rapide et efficace pour un beau piège !
    J'espère que le Collator saura passer l'obstacle, et considérer qu'un espace insécable = un espace, faute de quoi je vais être à terme dans de gros troubles.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Oui, la plupart des Collator réglés sur PRIMARY considèrent qu'un espace insécable et un espace normal sont équivalents.
    Par contre ils voient ça comme une différence secondaire, donc un Collator obtenu par défaut sans changer la sensibilité considérera qu'ils sont différents.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    605
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 605
    Points : 670
    Points
    670
    Par défaut
    Tu as bien failli me gâcher mon Dimanche !
    Car bien que tu aies raison,

    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
       /**
        * Tests d'un collator.
        */
       @Test public void collator()
       {
          int décomposition = Collator.CANONICAL_DECOMPOSITION;
     
          Collator c1 = Collator.getInstance(Locale.FRANCE);
          c1.setDecomposition(décomposition);
          c1.setStrength(Collator.PRIMARY);
     
          Collator c2 = Collator.getInstance(Locale.FRANCE);
          c2.setDecomposition(décomposition);
          c2.setStrength(Collator.SECONDARY);
     
          Collator c3 = Collator.getInstance(Locale.FRANCE);
          c3.setDecomposition(décomposition);
          c3.setStrength(Collator.TERTIARY);
     
          // Les espaces insécables.
          String s1 = " "; //$NON-NLS-1$
          String s2 = "\u00a0"; //$NON-NLS-1$ // Espace insécable.
          System.out.println("Collator(PRIMARY).compare(espace, espace insécable) = 0 ? " + (c1.compare(s1, s2) == 0)); //$NON-NLS-1$
          System.out.println("Collator(SECONDARY).compare(espace, espace insécable) =  0 ? " + (c2.compare(s1, s2) == 0)); //$NON-NLS-1$
          System.out.println("Collator(TERTIARY).compare(espace, espace insécable) =  0 ? " + (c3.compare(s1, s2) == 0)); //$NON-NLS-1$
     
          // Les autres caractères.
          String s3 = "Aaé"; //$NON-NLS-1$
          String s4 = "aae"; //$NON-NLS-1$
          System.out.println("Collator(PRIMARY).compare(\"Aaé\", \"aae\") =  0 ? " + (c1.compare(s3, s4) == 0)); //$NON-NLS-1$
          System.out.println("Collator(SECONDARY).compare(\"Aaé\", \"aae\") =  0 ? " + (c2.compare(s3, s4) == 0)); //$NON-NLS-1$
          System.out.println("Collator(TERTIARY).compare(\"Aaé\", \"aae\") =  0 ? " + (c3.compare(s3, s4) == 0)); //$NON-NLS-1$
     
          String s5 = "Aa"; //$NON-NLS-1$
          String s6 = "aa"; //$NON-NLS-1$
          System.out.println("Collator(PRIMARY).compare(\"Aa\", \"aa\") =  0 ? " + (c1.compare(s5, s6) == 0)); //$NON-NLS-1$
          System.out.println("Collator(SECONDARY).compare(\"Aa\", \"aa\") =  0 ? " + (c2.compare(s5, s6) == 0)); //$NON-NLS-1$
          System.out.println("Collator(TERTIARY).compare(\"Aa\", \"aa\") =  0 ? " + (c3.compare(s5, s6) == 0)); //$NON-NLS-1$
       }
    (Remarque : le test unitaire devrait bien sûr faire des assertTrue et des assertFalse plutôt que des System.out.println(), mais là il sert juste pour donner une vue d'ensemble du comportement de la fonction Collator.compare.)


    donnant ce résultat là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Collator(PRIMARY).compare(espace, espace insécable) = 0 ? true
    Collator(SECONDARY).compare(espace, espace insécable) =  0 ? false
    Collator(TERTIARY).compare(espace, espace insécable) =  0 ? false
    Collator(PRIMARY).compare("Aaé", "aae") =  0 ? true
    Collator(SECONDARY).compare("Aaé", "aae") =  0 ? false
    Collator(TERTIARY).compare("Aaé", "aae") =  0 ? false
    Collator(PRIMARY).compare("Aa", "aa") =  0 ? true
    Collator(SECONDARY).compare("Aa", "aa") =  0 ? true
    Collator(TERTIARY).compare("Aa", "aa") =  0 ? false
    C'était assez choquant d'un point de vue linguistique. Dans aucune langue les livres de grammaire, d'orthographe ou même de phonétique n'ont jamais évoqué l'espace insécable pour lui attribuer une quelconque action sur quoi que ce soit. Alors qu'il se mette à semer le foin dès le strength SECONDARY, il y avait de quoi hululer.

    Par chance, si tu passes en décomposition FULL_DECOMPOSITION, il résout ce problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Collator(PRIMARY).compare(espace, espace insécable) = 0 ? true
    Collator(SECONDARY).compare(espace, espace insécable) =  0 ? true
    Collator(TERTIARY).compare(espace, espace insécable) =  0 ? true
    Collator(PRIMARY).compare("Aaé", "aae") =  0 ? true
    Collator(SECONDARY).compare("Aaé", "aae") =  0 ? false
    Collator(TERTIARY).compare("Aaé", "aae") =  0 ? false
    Collator(PRIMARY).compare("Aa", "aa") =  0 ? true
    Collator(SECONDARY).compare("Aa", "aa") =  0 ? true
    Collator(TERTIARY).compare("Aa", "aa") =  0 ? false
    Bien sûr, au prix d'une plus grande lenteur, mais je suis quand même assez pour les fonctions qui donnent des résultats justes...

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Ah mais oui, je suis con, j'y avais pas pensé -_-°.

    Bon, jouer sur la décomposition Unicode non-canonique, ça marche aussi.
    Ceci étant, en réfléchissant et s'il restait une difficulté, ça t'aurait rien coûté de juste virer les espaces insécables avant de faire la comparaison. Après tout, tu sais qu'il font partie des formats des nombres et donc qu'ils peuvent apparaître. Bah s'ils t'arrangent pas c'est pas compliqué de les faire disparaître -_-°.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

Discussions similaires

  1. Récupérer une chaîne renvoyée par un exécutable
    Par alexandre2012 dans le forum VBScript
    Réponses: 0
    Dernier message: 30/01/2012, 11h51
  2. lock d'une ligne renvoyée par un select
    Par jdelges dans le forum DB2
    Réponses: 9
    Dernier message: 13/04/2007, 14h20
  3. Réponses: 2
    Dernier message: 15/09/2006, 12h07
  4. [SQL] php et recuperation d'une valeur renvoyée par une fonction sql
    Par highman dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 21/06/2006, 15h42
  5. Vérifier qu'une chaîne commence par
    Par BenoitDenis dans le forum Langage
    Réponses: 5
    Dernier message: 02/05/2006, 12h00

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