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 :

Comment détecter la présence de caractères UTF-8 dans une chaîne qui n'aurait pas dû en avoir ?


Sujet :

Collection et Stream Java

  1. #1
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 607
    Points : 671
    Points
    671
    Par défaut Comment détecter la présence de caractères UTF-8 dans une chaîne qui n'aurait pas dû en avoir ?
    Bonjour,

    Je mets au point un driver sur une vieille base de données DBase 3+, qui date d'assez longtemps (fin 1980 - début 1990).
    Les champs textes qu'elle déclare portent les caractères que les gens y mettent, mais cette base ne savait pas à l'époque que des caractères UTF-8 pourraient y être écrits, et ceux qui emploient ces bases de nos jours, eux, ne savent pas qu'elles ne les soutient pas. Donc, ils en mettent à l'occasion.

    Et en lisant un champ, je peux obtenir ceci : "Bagneux", ou cela : "Asnières-sur-Seine".
    Dans le deuxième cas, de manière silencieuse, j'aimerais pouvoir détecter immédiatement qu'il y a un problème d'encodage.

    1) Est-ce que parmi les méthodes de la classe Character certaines vont pouvoir m'aider ? Je vois des méthodes telles que isUnicodeIdentifierStart(...) et d'autres, mais s'activeront-elles appliquées à une chaîne de caractères qui ne se croit justement pas UTF-8 et qui à l'instant où on lui pose la question pense qu'elle est ISO-8859-1 ou cp1252 ?

    2) Mr Sauvage a un algorithme brutal sinon :
    Chaîne 1 : la chaine originale.
    Chaîne 2 : la chaine convertie en UTF-8

    Si (chaîne 2.length() < chaîne 1.length()) Alors on devrait préférer Chaîne 2.

    En partant de la constatation qu'une chaîne mal encodée a très souvent (... mais pas toujours !) une taille en caractères supérieure à celle qu'elle aurait dû avoir à cause des caractères parasites qui se sont insérés dedans.
    Mais c'est évidement atroce comme méthode !

    Que me suggérez-vous ?

    Merci,

    Grunt.


    P.S. : Je peux difficilement éviter une des célèbres parodies qui s'applique aux problèmes de conversion de caractères :
    Nom : 1375856126_small.jpg
Affichages : 743
Taille : 24,8 Ko

  2. #2
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 559
    Points : 21 621
    Points
    21 621
    Par défaut
    Hello,

    Citation Envoyé par grunt2000 Voir le message
    1) Est-ce que parmi les méthodes de la classe Character certaines vont pouvoir m'aider ? Je vois des méthodes telles que isUnicodeIdentifierStart(...) et d'autres, mais s'activeront-elles appliquées à une chaîne de caractères qui ne se croit justement pas UTF-8 et qui à l'instant où on lui pose la question pense qu'elle est ISO-8859-1 ou cp1252 ?
    Non, ces classes ne t'aideront pas.
    Il faut comprendre qu'en Java, une String ou un Character n'ont pas d'encodage. Les données qu'on lit dans un fichier, ou une base de données, ou ce genre de choses, ça ça a un encodage. Notamment ce que tu as dans ta base de données, ok, il y a un genre de clash mais en tout cas ça a un encodage.
    Mais tout ça c'est décodé avant d'être transformé en String.

    Du coup les classes String et Character n'ont pas de notion d'encodage à t'offrir (la classe String peut tout juste convertir une String en octets et vice-versa en utilisant un encodage.)

    Citation Envoyé par grunt2000 Voir le message
    2) Mr Sauvage a un algorithme brutal sinon :
    Chaîne 1 : la chaine originale.
    Chaîne 2 : la chaine convertie en UTF-8

    Si (chaîne 2.length() < chaîne 1.length()) Alors on devrait préférer Chaîne 2.

    En partant de la constatation qu'une chaîne mal encodée a très souvent (... mais pas toujours !) une taille en caractères supérieure à celle qu'elle aurait dû avoir à cause des caractères parasites qui se sont insérés dedans.
    Mais c'est évidement atroce comme méthode !
    A priori ça me paraît pas plus bête qu'autre chose. Comme tu le remarques si bien il n'y a pas d'algorithme certain, c'est un peu ça le principe des encodages.

    Moi quand j'ai ce genre de problématique j'aime bien les solutions suivantes :

    #Approche 1 - Quand les données que j'ai ne sont pas très ésotériques (genre des noms de villes françaises, des prénoms qui peuvent s'écrire en français, ce genre de choses.)

    Je fais une liste des caractères qui pourraient possiblement apparaître. Si une chaîne contient des caractères qui n'y sont pas (genre à ou ¨ ou ©, on en a pas dans les noms français,) c'est sûrement qu'elle est pas en windows-1252.

    #Approche 2 - quand la 1 n'est pas applicable.

    - Je regarde si la chaîne est entièrement ASCII. Si oui, ça n'a pas d'importance.
    - Si non, j'essaie de l'interpréter en utf-8 au lieu de windows-1252, et je compte le nombre d'occurrences du caractère '\ufffd', qui représente une erreur de décodage. S'il n'y en a pas, la chaîne est probablement en utf-8. S'il y en a, elle n'est probablement pas utf-8.

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Tu pourrais t'appuyer sur la méthode decode(ByteBuffer) de CharsetDecoder qui envoie une exception si la chaine n'est pas conforme.

    Dans le principe, tu récupères une instance de Charset pour un encodage donné et tu testes ta chaine.
    Si tu as une exception, c'est qu'elle n'est pas compatible et tu testes avec un autre CharsetDecoder jusqu'à trouvé le bon.

    Ceci dit, ça te donnera une compatibilité avec un charset, pas forcément celui d'origine.

  4. #4
    Membre éclairé

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 607
    Points : 671
    Points
    671
    Par défaut
    Merci !
    En combinant une sauce faite à partir de la taille des chaînes converties et la détection des caractères \ufffd, je suis parvenu à un résultat convenable.

  5. #5
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 886
    Points : 3 725
    Points
    3 725
    Par défaut
    Salut,

    Et la méthode String getEncoding(), vous en pensez quoi ?

  6. #6
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 559
    Points : 21 621
    Points
    21 621
    Par défaut
    J'en pense qu'elle n'existe pas, ce qui est un inconvénient difficile à surmonter .

  7. #7
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 886
    Points : 3 725
    Points
    3 725
    Par défaut
    Ah bon ? J'ai vu cela pourtant : http://www.tutorialspoint.com/java/i...etencoding.htm

    Est-ce une erreur ?

  8. #8
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 559
    Points : 21 621
    Points
    21 621
    Par défaut
    ... Ok, je pensais que tu voulais dire "la méthode getEncoding() de la classe String" -_-°.
    Des méthodes getEncoding() il y en a à foison dans toutes les classes du monde.

    Alors, la méthode getEncoding() de la classe InputStreamReader. Dans le cas qui nous intéresse elle n'est pas concernée, parce que :
    - Il n'y a pas de InputStreamReader dans l'histoire. Il lit des données d'une base de données.
    - Cette méthode sert à redemander quel est l'encodage qui avait été décidé. Or le problème ici, c'est que l'encodage qui avait été décidé n'est pas celui qui a été utilisé. Dans ce cas il ne reste plus qu'à essayer de deviner quel est celui qui a été utilisé à la place, et aucune méthode ne fera ça pour nous parfaitement.

  9. #9
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 886
    Points : 3 725
    Points
    3 725
    Par défaut
    Oui effectivement j'ai testé et ça ne fait pas ce que je pensais...

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 07/02/2013, 18h36
  2. Réponses: 3
    Dernier message: 18/11/2009, 01h25
  3. Détecter saut de ligne dans une chaîne de caractères
    Par link256 dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 30/03/2009, 15h25
  4. Réponses: 2
    Dernier message: 15/09/2006, 12h07
  5. Comment remplacer plusieurs caractères dans une chaîne?
    Par Antigonos Ier Gonatas dans le forum Général Python
    Réponses: 5
    Dernier message: 16/06/2006, 16h04

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