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

avec Java Discussion :

décoder une chaîne de caractères comprenant \xc3\xa9 (UTF-8 littéral)


Sujet :

avec Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    764
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2008
    Messages : 764
    Par défaut décoder une chaîne de caractères comprenant \xc3\xa9 (UTF-8 littéral)
    Bonjour,

    Je souhaite décoder de l'encodage UTF-8 littéral.

    Par exemple, je reçoit une String qui contient ceci : "\xc3\xa9" et je souhaiterais décoder/transformer cela par le caractère 'é'.
    En fait cette chaîne que je reçois d'une appli mobile Android correspond au codage UTF-8 littéral et ce codage fait référence à une multitudes de caractères. Par exemple la chaîne "\xc3\xa0" représente le caractère 'à' ou alors la chaîne "\xc3\x9f" représente le caractère de l'alphabet Allemand 'ß'.

    J'ai essayé de trouver des solutions avec UriComponent mais cela ne concerne que les URI contenues dans les adresses internet.

    J'ai essayé aussi avec le code ci-dessous mais je retrouve en sortie exactement la même chaîne qu'en entrée ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    String strSortie = null;
    try {
    	strSortie = new String(strEntree_.getBytes(), "utf8");
    } catch (UnsupportedEncodingException e1) {
    	e1.printStackTrace();
    }
    J'ai lu dans un autre post qu'il faut traiter cette chaîne avec les bits mais là je ne sais pas trop comment faire.

    Si quelqu'un à une piste, je vous en remercie !

  2. #2
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Hello,

    ce que tu as besoin de comprendre, c'est qu'un encodage comme UTF-8, ça sert à transformer des octets en String et des String en octets.
    Je suppose que tout le monde te l'a dit, un ordinateur c'est des zéros et des uns. Donc c'est fait de bits, et avec 8 bits tu as un octet. Un ordinateur et tout ce qui passe dedans, c'est fait d'octets.
    Quand tu veux transformer ces octets en texte, comme par exemple "Bonjour tout le monde" qui ne ressemble pas à des zéros et des uns, tu dois simplement passer par un procédé qui transforme les octets en texte. Et UTF-8 est l'un de ces procédés.

    Ce qui signifie que quand tu cherches à utiliser UTF-8, quand tu veux obtenir une String tu dois lui donner des octets. Et pas autre chose que des octets, parce que c'est à ça qu'il sert et pas à autre chose.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    byte[] bytes = {(byte)0xc3, (byte)0xa9};
    String text = new String(bytes, StandardCharsets.UTF_8);
    System.out.println(text);
    Voilà une utilisation parfaitement normale d'UTF-8. Comme tu peux le constater, ça affiche é.

    Ton problème, c'est que ce que tu as, ce ne sont pas des octets, ce sont des String qui contiennent des trucs bizarres comme \xc3 à l'intérieur.

    Tu dois donc résoudre ce problème en deux étapes :

    #1 - convertir tes Strings en octets

    #2 - convertir ces octets en String en utilisant UTF-8 comme je l'ai montré.

    La partie #1 me semble de loin la plus difficile, dans la mesure où je ne connais pas de méthode directe pour le faire. Et qu'on ne connaît pas facilement à l'avance le nombre d'octets.

    Voici un début de méthode qui te permettra de faire cette conversion, mais je ne vais pas la faire entièrement pour toi :

    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
    public static byte[] convertEncodedToBytes(String encoded) {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
     
      for(int i = 0; i < encoded.length();) {
        char ch = encoded.charAt(i);
        if(ch == '\\') { // si on est sur un truc genre \xc3
     
          if(encoded.length() < i + 4) {
            throw new IllegalArgumentException("Incorrect string encoded, found incomplete \\");
          }
          if(encoded.charAt(i+1) != 'x') {
            throw new IllegalArgumentException("Incorrect string encoded, found \\ not followed by x");
          }
     
          String hexabytes = encoded.substring(i+2, i+4); // récupérer la partie c3
          byte decodedHexByte = (byte)Integer.parseUnsignedInt(hexabytes, 16); // convertir l'octet qu'elle encode
     
          out.write(decodedHexByte);
     
          i += 4;
     
        } else {
        	// sinon, à toi de finir
        	i++;
        }
      }
     
      return out.toByteArray();
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Tu peux essayer avec StringEscapeUtils.unescapeECMAScript() de apache commons lang 3. Comme les literals de la forme \x sont reconnus par ce langage, ça devrait faire le travail. Sinon comme mentionné au dessu, y aller à la main.

  4. #4
    Membre éclairé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    764
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Février 2008
    Messages : 764
    Par défaut
    Bonjour,

    Je vous remercie pour vos aides très intéressantes !

    J'ai trouvé une solution à mon problème :

    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
     
    	/**
             * replaces e.g. "\xc3\xa9" with "é"
             *
             * @param s the input
             * @return the output
             */
    	public static String unescapeMultiByteUtf8Literals(final String s) {
    		try {
    			final String q = new String(unescapeByte(s.getBytes("UTF-8")), "UTF-8");
    			//			if (!q.equals(s)) {
    			//				LOG.log(Level.SEVERE, "multi byte utf literal found:\n" +
    			//							"  orig = " + s + "\n" +
    			//							"  escp = " + q
    			//				);
    			//			}
    			return q;
    		} catch (Exception e) {
    			//			LOG.log(Level.SEVERE, "Could not unescape multi byte utf literal - will use original input: " + s, e);
    			return s;
    		}
    	}
     
    	private static byte[] unescapeByte(final byte[] escaped) throws Exception {
    		// simple state machine iterates over the escaped bytes and converts
    		final byte[] unescaped = new byte[escaped.length];
    		int posTarget = 0;
    		for (int posSource = 0; posSource < escaped.length; posSource++) {
    			// if its not special then just move on
    			if (escaped[posSource] != '\\') {
    				unescaped[posTarget] = escaped[posSource];
    				posTarget++;
    				continue;
    			}
    			// if there is no next byte, throw incorrect encoding error
    			if (posSource + 1 >= escaped.length) {
    				throw new Exception("String incorrectly escaped, ends with escape character.");
    			}
    			// deal with hex first
    			if (escaped[posSource + 1] == 'x') {
    				// if there's no next byte, throw incorrect encoding error
    				if (posSource + 3 >= escaped.length) {
    					throw new Exception("String incorrectly escaped, ends early with incorrect hex encoding.");
    				}
    				unescaped[posTarget] = (byte) ((Character.digit(escaped[posSource + 2], 16) << 4) + Character.digit(escaped[posSource + 3], 16));
    				posTarget++;
    				posSource += 3;
    			}
    			// deal with n, then t, then r
    			else if (escaped[posSource + 1] == 'n') {
    				unescaped[posTarget] = '\n';
    				posTarget++;
    				posSource++;
    			} else if (escaped[posSource + 1] == 't') {
    				unescaped[posTarget] = '\t';
    				posTarget++;
    				posSource++;
    			} else if (escaped[posSource + 1] == 'r') {
    				unescaped[posTarget] = '\r';
    				posTarget++;
    				posSource++;
    			} else if (escaped[posSource + 1] == '\\') {
    				unescaped[posTarget] = escaped[posSource + 1];
    				posTarget++;
    				posSource++;
    			} else if (escaped[posSource + 1] == '\'') {
    				unescaped[posTarget] = escaped[posSource + 1];
    				posTarget++;
    				posSource++;
    			} else {
    				// invalid character
    				throw new Exception("String incorrectly escaped, invalid escaped character");
    			}
    		}
    		final byte[] result = new byte[posTarget];
    		System.arraycopy(unescaped, 0, result, 0, posTarget);
    		// return byte array, not string. Callers can convert to string.
    		return result;
    	}
     
    @POST
    @Path("/send_photo")
    @Consumes(MediaType.MULTIPART_FORM_DATA + ";charset=utf-8")
    public Response insertPhoto(@FormDataParam("photo_fileStream") InputStream photo_fileStream_,
    	@FormDataParam("comment") String comment{
     
    comment = unescapeMultiByteUtf8Literals(comment);
     
    .....
    }

  5. #5
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Oui bah, même chose mais en complet et un chouïa plus performant.

    Content que tu aies pu le trouver quelque part. Personnellement j'aurais préféré utiliser une bibliothèque externe comme le disait tchize_, mais je ne savais pas à quel nom chercher cet encodage.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Joli code bien propre.

    Deux petites remarques,
    • tu peux te passer du dernier arrayCopy, String a un constructeur qui prend byte[], offset, length et charset
    • Vu que ton algorithme donne toujours un résultat plus court, tu lit toujours en avance (ou à égalité) avec là ou tu écris. Tu peux remplacer directement les bytes dans ton tableau source. et te passer de ton tableau destination.

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 09/03/2016, 14h21
  2. Réponses: 8
    Dernier message: 12/02/2013, 01h08
  3. [PHP 4] décoder une chaîne de caractères
    Par gorgorbhey dans le forum Langage
    Réponses: 2
    Dernier message: 30/03/2009, 18h48
  4. Inverser une chaîne de caractères
    Par DBBB dans le forum Assembleur
    Réponses: 2
    Dernier message: 30/03/2003, 11h09
  5. Réponses: 3
    Dernier message: 09/05/2002, 01h39

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