[java] code ascii d'un char mais en unicode 8

Résolu
sbouli Messages postés 208 Statut Membre -  
sbouli Messages postés 208 Statut Membre -
Bonjour,

Je cherche pour décompresser une chaine codée en lzw, à obtenir le code ascii d'un caractère, pour le moment si je fait :

public static int toASCII(char lettre)
{
return (int)lettre;
}

il me retourne la valeur unicode sur 16 bits et pas 8 bits par exemple Ä renvoi 65533 et pas 257 ...

évidement la chaine étant encodé par différent language (les clients varies) il faut que je puisse travailler en UTF 8

J'ai essayé de convertir ma string dès le départ avec :

byte[] utf8Bytes = txt2decode.getBytes("UTF8");
txt2decode = new String(utf8Bytes, "UTF8");

mais ça n'a rien changé ... pour infos ma boucle à cette tête :
String[] splitStr = txt2decode.split("") ;
for (i = 0 ; i < length ; i++) {
String current = splitStr [i] ;
int code = toASCII(txt2decode.charAt(i));

.....

}

Merci d'avance.

Stéphane
Configuration: Windows XP
Safari 525.13

7 réponses

  1. sbouli Messages postés 208 Statut Membre 2
     
    Hello,

    En fait je me suis mal expliqué ... je cherche à décompresser des strings compressées en utilisant l'algo de compression LZW. Pour le moment la compression à lieu en FLASH Action Script 3.
    Or lors de la décompression en flash de la même chaine, lorsque j'arrive sur un caractère type ã (ou Ä) j'obtiens avec la fonction var code:int = txt2decode.charCodeAt(i) ;
    des codes > 255 c'est même tout l'intéret de l'algo.
    Lorsqu'il trouve des séquences identique, il leur attribue une place dans le dico et met dans la chaine l'index de cette séquence dans le dico. par exemple "<c" est inséré dans le dico en position 257 et le caractère dont le code "ascii" correspond à 257 est inséré dans la string compressée.

    toute la difficulté est de convertir la fonction AS3 (flash 9) charCodeAt() en java ...

    Voici le code compression/decompression en flash as3 :

    
             //conversion en AS3 de l'algorythm de Zeh Fernando version 1.0.0
    	
    	public class LZW {
    		
    		static var headerversion:String = "v1.0";
    		
    		// ===============================================================
    		// COMPRESSION function -------------------------------------
    		public static function compress (txt2encode:String): String {
    			
    			var dico:Array = new Array() ;
    			for ( var i:int =0 ; i<256 ; i++)    dico[ String.fromCharCode (i) ] = i ;
    			var result:String = "";
    			var splitStr:Array = txt2encode.split("") ;
    			var length:int = splitStr.length ;
    			var nbChar:int = 257 ; // Nombres de caractères courant dans le dictionnaire
    			var buffer:String = "" ; // initialisation du tampon buffer
    			
    			for (i=0 ; i <= length  ; i++) {
                 	var current = splitStr[i] ;
    				if ( dico[ buffer + current ] !== undefined ) {
    					buffer += current ;
    				} else {
    					result += String.fromCharCode ( dico[buffer] ) ;
    					dico [buffer + current] = nbChar++;
    					buffer = current ;
    				}
    			}
    			return (headerversion+result);
    		}
    		// ===============================================================
    		// FAST DECOMPRESSION function -----------------------------------
    		public static function decompress (txt2decode:String): String {
    			
    			txt2decode = txt2decode.substring(headerversion.length);// on supprime le  header "v1.0"
    			
    			var dico:Array = new Array() ;
    			for ( var i:int =0 ; i<256 ; i++) {
    				var c:String = String.fromCharCode (i) ;
    				dico[c] = c ;
    			}
    			var splitStr:Array = txt2decode.split("") ;
    			var length:int = splitStr.length ;
    			var nbChar:int = 257; // nombre de caractère courant dans le dictionnaire
    			var buffer:String = "" ; // initialisation du tampon mémoire
    			var chaine:String = "" ; // chaine temporaire
    			var result:String = "" ; // chaine retournée à la fin de la décompression
    			for (i = 0 ;  i < length ; i++) {
    				var current:String = splitStr [i] ;
    				var code:int = txt2decode.charCodeAt(i) ;
    				
    				//trace("code "+code+" "+splitStr[i]);
    				
    				if (buffer == "") {
    					buffer = current ;
    					result += current ;
    				} else {
    					if ( code <= 256 ) {
    						result += current ;
    						chaine = buffer + current ;
    						dico[nbChar] = chaine ;
    						nbChar ++ ;
    						buffer = current ;
    					} else {
    						chaine = dico [code] ;
    						result += chaine ;
    						dico [nbChar] = buffer + chaine.slice (0, 1);
    						nbChar ++ ;
    						buffer = chaine ;
    					}
    				}
    			}
    			return result;
    		}
    		// ===============================================================
    	
    	
    	}//public class LZW
    
    


    Pour infos, l'exemple de chaine que je compresse est :
    "<call>
    <cmd>login</cmd>
    <callback>login</callback>
    <id_membre>255</id_membre>
    <id_site>0</id_site>
    <pseudo>toto</pseudo>
    </call>"

    qui devient quelque chose comme (je suis pas sûr que le debugger + le copier/coller préserve les caractères ...) :

    <call>āmd>login</cċĆĈāălbackčďđēĂĄĜĞėĉid_membre>255ēĪĬĮİIJćĩīsitIJ0ķĿŁļĘpseudo>toőēŊŌŎĆģĚ>"""

    Merci pour ton aide !!
    1
  2. in2ni
     
    Il me semble que java travaille en interne avec des caractères UTF-16. Donc, le code d'un caractère d'une chaîne java est renvoyé en UTF-16.

    C'est une bonne idée de travailler à partir d'un tableau d'octets grâce à getBytes ("UTF8");
    Mais il ne faut pas reconvertir ce tableau en chaîne, car java semble alors les retraduire implicitement en UTF16

    As-tu essayé tout simplement :

    int length = txt2decode.length();
    byte[] utf8Bytes = txt2decode.getBytes ("UTF8");
    for (int i = 0; i < length; i++)
    {
    int code = utf8Bytes[i];
    ...
    }
    0
  3. sbouli Messages postés 208 Statut Membre 2
     
    bonjour,

    bizarrement, il me renvoi -61 pour le Ä .... mais on progresse :)

    Merci
    0
  4. in2ni
     
    Tu as un tableau de bytes. Les bytes java sont codés de -128 à 128, je crois.
    Il faut peut-être les convertir avec l'opération & 0xff pour les rétablir dans la tranche entre 0..255

    Essaie ça et dis-moi :

    int length = txt2decode.length();
    byte[] utf8Bytes = txt2decode.getBytes ("UTF8");
    for (int i = 0; i < length; i++)
    {
    int code = utf8Bytes[i] & 0xff;
    ...
    }
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. in2ni
     
    Tu as un tableau de bytes. Les bytes java sont codés de -128 à 128, je crois.
    Il faut peut-être les convertir avec l'opération & 0xff pour les rétablir dans la tranche entre 0..255

    Essaie ça et dis-moi :

    int length = txt2decode.length();
    byte[] utf8Bytes = txt2decode.getBytes ("UTF8");
    for (int i = 0; i < length; i++)
    {
    int code = utf8Bytes[i] & 0xff;
    ...
    }
    0
    1. sbouli Messages postés 208 Statut Membre 2
       
      désolé mais toujours pas, il me renvoi 63 pour le Ä et pas 257

      j'ai du mal à comprendre le coup du -128/+128 ....

      voila mon code actuel pour la décompression LZW :
      
      public static String decompress(String txt2decode) throws UnsupportedEncodingException {
      		//txt2decode2 = txt2decode.getBytes("UTF8");
      		txt2decode = txt2decode.substring(headerversion.length());// on supprime le  header "v1.0"
      		
      	     
      	    
      		
      		Map dico = new HashMap() ;
      		Integer i;
      		for ( i =0 ; i<256 ; i++) dico.put(toChar(i), toChar(i));
      		int length = txt2decode.length();
      		byte[] utf8Bytes = txt2decode.getBytes("ISO-8859-1"); 
      		//String[] splitStr = txt2decode.split("") ;
      		//int length = splitStr.length ;
      		int nbChar = 257; // nombre de caractère courant dans le dictionnaire
      		String buffer = "" ; // initialisation du tampon mémoire
      		String chaine = "" ; // chaine temporaire
      		String result = "" ; // chaine retournée à la fin de la décompression
      		for (i = 0 ;  i < length ; i++) {
      			//String current = splitStr [i] ;
      			//int code = toASCII(txt2decode.charAt(i));
      			int code = utf8Bytes[i]& 0xff;
      			String current = ""+toChar(code);
      			if (buffer == "") {
      				buffer = current ;
      				result += current ;
      			} else {
      				if ( code <= 256 ) {
      					result += current ;
      					chaine = buffer + current ;
      					dico.put(nbChar, chaine);
      					nbChar ++ ;
      					buffer = current ;
      				} else {
      					chaine = (String) dico.get(code);
      					result += chaine ;
      					
      					dico.put(nbChar, buffer + chaine.substring(0, 1));
      					nbChar ++ ;
      					buffer = chaine ;
      				}
      			}
      		}
      		return result;
      	}
      
      
      0
      1. in2ni > sbouli Messages postés 208 Statut Membre
         
        Je m'aperçois que tu utilises
        byte[] utf8Bytes = txt2decode.getBytes("ISO-8859-1");

        ce ne serait pas plutôt
        byte[] utf8Bytes = txt2decode.getBytes("UTF-8");

        Si Ä n'est pas connu dans un charset (jeu de caractère), il sera interprété comme '?' (code 63 !)
        Par exemple :
        bytes[] b = "Ä".getBytes("US-ASCII");
        System.out.println (b[0] & 0xff); ==> affichera 63

        Généralement, les langages considèrent le byte (octet) comme un entier positif dont la valeur peut être comprise entre 0 et 255. Mais les concepteurs de java ont décidé qu'il s'agissait d'un entier signé, dont la valeur minimale commence à -128 et la valeur maximale est à +127. C'est une convention, mais pour faire correspondre des bytes (et non pas des char) avec les valeurs ASCII habituelles (0..255), il ne faut pas oublier de les convertir en entiers non signés, grâce à & 0xff.

        Je testerai ton programme demain. Mais essaie de changer le charset utilisé dans la création de ton tableau de bytes en utilisant getBytes("UTF-8"), si tu es bien sûr que ta chaîne d'origine est de l'UTF-8, évidemment (à vérifier !)
        0
      2. sbouli Messages postés 208 Statut Membre 2 > in2ni
         
        Hello,

        Merci encore pour ton aide, malheureusement, j'ai essayé un peu tous les charsets sans résultat. Si je met UTF-8 (celui qui me parait le plus approprié), j'obtient -61 (sans le &0xff) pour le Ä ou 195 (avec le &0xff) alors que je voudrais 257 ....

        ça m'agace ...

        pour la souce du string, il vient pour le moment de clients en flash (CS 9) dont personne n'est capable de me dire en quel charset il est codé ...

        Stéphane
        0
      3. in2ni > sbouli Messages postés 208 Statut Membre
         
        En essayant ma fonction, j'obtiens deux bytes pour le Ä en UTF-8 :
        printBytes ("Ä", "UTF-8");
        ==> 195 132

        Pourquoi cherches-tu as obtenir le byte 257 ? C'est impossible : on lit une chaîne d'octets, qu'on convertit dans la tranche 0..255, impossible donc d'avoir des valeurs supérieures à 255 !
        0
      4. sbouli Messages postés 208 Statut Membre 2 > in2ni
         
        j'ai répondu plus bas dans le thread mais comme je suis pas sûr que tu reçoives un email, je répond aussi directement à ton post.

        Stéphane
        0
  7. in2ni
     
    Une petite fonction utile qui imprime les octets d'une chaîne en fonction de l'encodage choisi..
    NB ici la conversion des byte java -128..127 en 0..255 (int) se fait implicitement par la lecture avec read() dans un flux ByteArrayInputStream.

    import java.io.*;
    import java.util.*;

    public class StringEncodings
    {
    public static void printBytes (String s, String charsetName) throws UnsupportedEncodingException
    {
    int length = s.length ();

    byte[] bytes = s.getBytes (charsetName);
    ByteArrayInputStream in = new ByteArrayInputStream (bytes);

    int byte255;
    while ((byte255 = in.read ()) != -1)
    {
    System.out.print (byte255 + " ");
    }
    System.out.println();
    }

    public static void main (String[] args) throws UnsupportedEncodingException
    {
    printBytes ("ÂÄÔÖÎÛÜ", "ISO-8859-1"); // encodage occidental
    printBytes ("ÂÄÔÖÎÛÜ", "UTF-16");
    printBytes ("ÂÄÔÖÎÛÜ", "UTF-8");
    }

    }
    0
  8. sbouli Messages postés 208 Statut Membre 2
     
    finalement, c'est bon, ce code est bon, (au détail du dernier caractère près), le pb venait essentiellement du socket qui modifiait la string à la réception, j'ai tout passé en UTF-8 et ça tourne nickel !!!

    Merci encore pour votre aide, ça m'a énormément fait avancer !!

    Stéphane
    0