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 :

Identifier qu'une chaine a un caractère non ANSI


Sujet :

Java

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    173
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 173
    Points : 187
    Points
    187
    Par défaut Identifier qu'une chaine a un caractère non ANSI
    Bonjour,
    J'ai une chaine stockée en base de données qui correspond à des adresses et qui n'est censé contenir que des caractères ANSI. Or, cela n'est pas toujours le cas (les données sont incorrecte alors).
    Exemple: '13 rue de lavion' en base de données

    J'écris dans un fichier de sortie en StandardCharsets.ISO_8859_1. Quand j'ouvre ce fichier dans Notepad++, une telle adresse s'affiche avec un caractère bizarre (comme 'CAN' par exemple au lieu du carré) et le fichier produit ne peut pas être exploité. Le caractère ne semble donc pas reconnu en ANSI.

    Ma question est: Au moment où je récupère en base la chaine de caractère dans un String, est-ce qu'il y a un moyen de vérifier si tout les caractères correspondent à un caractère correspondant au charset ISO_8859_1 afin de partir un erreur si ce n'est pas le cas? (en gros je voudrais que pour la chaine citée en exemple, je parte en erreur car identifiée comme incorrecte à cause du caractère spécial).

    Le but est d'identifier ces cas avec une adresse incorrecte quand c'est traité afin de pouvoir remonter ces anomalies à l'équipe en charge de remplir la base de données.

    Je ne sais pas si je dois utiliser String.getBytes(Charset charset) car je vois qu'il est mis "This method always replaces malformed-input and unmappable-character sequences with this charset's default replacement byte array". Cela voudrait dire que je peux identifier un caractère mal formé ou inexistant en cherchant ce byte de remplacement par défaut?

    Ou la méthode CharsetEncoder.canEncode() (je ne sais pas si ca retournerait false dans mon cas)?

    Merci d'avance pour votre retour.

    SOLUTION

    Edit: voici la solution mise en place et qui semble fonctionner.
    En regardant mes fichiers j'ai vu que les caractères qui posent problème sont en fait des caractères de controle (non imprimable comme 'CAN', 'SO', 'STX'...).
    Je fais donc 2 checks:
    une méthode pour tester si c'est un caractère de controle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    /**
         * Return true if character is a control character according to unicode (not printable character)
         * @param pCharacter
         * @return
         */
        private boolean isControlCharacter(char character) {
            return character <= '\u001F';
        }
    Ainsi qu'un check en fonction de l'encodeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    CharsetEncoder encoder = Charset.forName("ISO-8859-1").newEncoder();
    encoder.canEncode(stringToCheck.charAt(index));
    La combinaison de ces 2 méthodes me permet d'identifier les lignes qui posent problème .

    Voici des liens utiles avec les tables pour l'ISO 8859-1 et les codes unicodes des caractères:
    http://www.dg77.net/tekno/xhtml/ascii.htm
    https://www.utf8-chartable.de/unicod...codeinhtml=dec
    Diplomes: DUT informatique et Master 2 MIAGE.
    Développeur Java/J2EE (principalement), .NET (niveau scolaire mais je compte m'améliorer ) et Web (HTML, PHP...).

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Tu es sûr que les données sont incorrectes dans la base ? Le problème ne vient-il pas de la façon de les récupérer ? C'est assez courant que la configuration Base de données/JDBC soit incorrecte pour la lecture des chaînes. La base est-elle bien configurée ? La chaîne de connexion est elle bien adéquate ? Le problème peut venir aussi de la manipulation de String et d'écriture dans le fichier.

    Il est par ailleurs étonnant que le É s'affiche sous forme de caractère de contrôle (), un caractère parfois utilisé comme caractère de remplacement, à priori un code 0x1a, qui existe bien en ISO-8859-1, mais pas celui utilisé par l'encodeur CharsetEncodeur/ISO-8859-1 du JDK (donc sun.nio.cs.ISO_8859_1) lors d'un encodage, qui plutôt 0x3f (à voir si l'implémentation de OPENJDK n'utiliserait pas 0x1a). La question est de savoir si le caractère est déjà le caractère de contrôle dans le fichier, ou si c'est Notepad++ qui fait ce remplacement (sélection du mauvais charset dans Notepad++).

    String.getBytes(Charset charset) te permet d'obtenir un tableau d'octets dans l'encodage spécifié. Les caractères de la chaîne initiale non encodables dans cet encodage seront remplacés par un caractère de remplacement, qu'on peut obtenir par (pour ISO 8859 1) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CharsetEncoder encoder = StandardCharsets.ISO_8859_1.newEncoder();
    System.out.println(new String(encoder.replacement(), encoder.charset()));
    (ici avec mon JDK13 Oracle, 6310/3f16/?)

    Ce n'est pas cette méthode qui te permettra de tester si la chaîne originale contient des caractères mal encodés à l'écriture, puisqu'elle fait elle-même une conversion. Tu ne testerais donc pas la chaîne d'origine.

    CharsetEncoder.canEncode(char/CharSequence) te permet de tester si une chaîne peut être convertie avec/sans remplacement, donc si elle contient des caractères qui n'ont pas de correspondance dans l'ensemble de caractères. Si la chaîne est déjà en ISO-8859-1, c'est trop tard, "ISO-8859-1.canEncode" te répondra true forcément. Si elle ne contient que des codes du charset ISO-8859-1, alors qu'elle est encodée dans un encodage dont ISO-8859-1 est un sous-ensemble (comme UTF-8 par exemple), c'est aussi trop tard pour utiliser canEncode().

    On ne peut tester si une chaîne ne contient pas de caractères non encodables avec l'encodage de la chaîne elle-même, puisqu'elle ne contient que forcément que des caractères encodés dans le charset utilisé pour la créer.

    Mais on ne pourrait utiliser le caractère de remplacement de l'encodeur ISO-8859-1, pour détecter les "caractères incorrects" puisque c'est forcément un caractère de l'ensemble de caractères ISO-8859-1. Si c'est ?, on pourrait utiliser des heuristiques du genre "je sais que dans un nom de personne il ne peut y avoir des ?". Mais pas dans le cas général. Une adresse peut-elle contenir des ? Ou pas ? Difficile d'être certain. Et puis, ça dépend de ce que utilise l'encodeur comme caractère de remplacement.

    En revanche, si le caractère "incorrect" est toujours le caractère de contrôle 0x1a, tu peux le tester spécifiquement, car il est peut probable qu'il soit normalement utilisé dans des données comme un nom ou une adresse, par un String.indexOf() par exemple, ou String.contains()... cela pourra déjà traiter un certain nombre de cas...

    Mais ça ne voudra pas dire forcément que les données en base sont incorrectes, seulement que les données que tu récupères le sont, le problème pouvant venir de la la connexion JDBC.

    Si les données sont pourries en base de données, il faut s'intéresser à comment cette base est configurée, à ce qui écrit dans cette base de données. Sinon, il faut s'intéresser à ce qui lit ces données...

    A noter par ailleurs, que ANSI ne devrait pas être utilisé pour désigner un charset. C'est le nom de l’organisme américain de standardisation (American National Standards Institute) qui a mis au poins l'encodage ASCII et ce terme est confus. Il est souvent utilisé pour désigné l'encodage Windows-1252 (CP1252), qui n'est pas exactement l'encodage ASCII. Du coup, avec ANSI, on sait pas très bien de quoi on parle.

    Si par ANSI, tu parles de CP1252, qui est une extension de ISO-8859-1 (parfois dit "Latin-1" ou "latin1"), qui est une extension de ASCII. Il peut donc y avoir des caractères de ISO-8859-1 qui seront "remplacés" lors d'un affichage en CP1252.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    173
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 173
    Points : 187
    Points
    187
    Par défaut
    Merci pour ton retour. On s'est télescopé. J'ai trouvé une solution qui semble bien fonctionner dans mon premier post (il faut que je teste avec l'ensemble des cas qu'on a eu) .

    En fait ici dans l'exemple c'est effectivement un 'é' que j'avais mis (exemple bidon pour montrer le type de ce que j'ai en base de données quand je consulte avec SQLDeveloppeur) mais en fait c'est un apostrophe dans un de mes cas qui a été remplacé par un caractère de controle (CAN en l'occurence pour Cancel). Je modifie l'exemple. Après j'ai aussi d'autres caractères remplacés par d'autres caractères de controle ('SO', 'STX'...) et des lettres avec accents qui ont été remplacés par des caractères bizarres mais il faut que je retrouve le cas.

    Celui qui insère les données a identifié une des causes du problème à l'origine mais il en reste une autre qui n'est pas de son fait (l'adresse peut être forcée par un appelant sans contrôle du coup et c'est l'appelant qui utilise cette fonction a mauvais escient).

    Cependant, il y a des dizaines de millions d'adresses et donc beaucoup d'adresses où on a ce type d'erreur donc en attendant les corrections à l'origine, nous devons, à l'exploitation de ces données, identifier les cas d'erreur pour les remonter et ne pas les sortir dans le fichier de sortie.
    Diplomes: DUT informatique et Master 2 MIAGE.
    Développeur Java/J2EE (principalement), .NET (niveau scolaire mais je compte m'améliorer ) et Web (HTML, PHP...).

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par philou44300 Voir le message
    mais en fait c'est un apostrophe dans un de mes cas qui a été remplacé par un caractère de controle
    Attention, si c'est une apostrophe, cela peut être le U+2019 (RIGHT SINGLE QUOTATION MARK) ou le U+02BC (MODIFIER LETTER APOSTROPHE), deux caractères non encodable en ISO-8859-1, ce qui peut expliquer le remplacement. Les données dans la base sont peut être en UTF-8 finalement ? Un Normalizer pourrait te permettre de faire une conversion adéquate encodable en ISO-8859-1...
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    173
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 173
    Points : 187
    Points
    187
    Par défaut
    Citation Envoyé par joel.drigo Voir le message
    Attention, si c'est une apostrophe, cela peut être le U+2019 (RIGHT SINGLE QUOTATION MARK) ou le U+02BC (MODIFIER LETTER APOSTROPHE), deux caractères non encodable en ISO-8859-1, ce qui peut expliquer le remplacement. Les données dans la base sont peut être en UTF-8 finalement ? Un Normalizer pourrait te permettre de faire une conversion adéquate encodable en ISO-8859-1...
    Bonjour et bonne année.

    La donnée à l'origine doit être en UTF-8 surement mais dans la base de données on a déjà le "carré" à la place du caractère (comme dans l'exemple). Il doit y avoir un problème de conversion avant de mettre en base de données du coup non? En tout cas c'est ce que je me suis dis.

    Après, le prestataire à qui on envoie les adresses extraites attend de l'ISO 8859-1 d'où le fait qu'on fait un select en base, qu'on obtient donc un String (UTF-16 derrière non?) puis qu'on écrit dans un fichier en demandant de l'ISO 8859-1 comme codage des caractères (et là on a donc des caractères bizarres ou des caractères comme 'CAN', 'SO', 'STX'... selon les caractères remplacés surement).

    Le mieux serait d'avoir le même codage tout au long de la chaine à mon avis mais le prestataire attend un certain codage.

    Je vais regarder pour le Normalizer mais en quoi cela serait utile dans mon cas? Je ne fais qu'extraire d'une base dans un String puis écrire dans un fichier en ISO 8859-1. Cela peut servir lors de l'écriture?
    Diplomes: DUT informatique et Master 2 MIAGE.
    Développeur Java/J2EE (principalement), .NET (niveau scolaire mais je compte m'améliorer ) et Web (HTML, PHP...).

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/01/2007, 20h33
  2. Interdire une frappe d'un caractére non numérique
    Par fatati dans le forum C++Builder
    Réponses: 13
    Dernier message: 12/12/2006, 09h56
  3. pb concaténation d'une chaine avec un caractère
    Par P'tite Nélodie dans le forum C
    Réponses: 9
    Dernier message: 06/11/2006, 19h09
  4. Vérifier si une chaine contient des caractères spéciaux
    Par BenoitDenis dans le forum Langage
    Réponses: 4
    Dernier message: 05/07/2006, 16h26
  5. Réponses: 6
    Dernier message: 15/05/2006, 22h39

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