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

Résolu/Fermé
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
- 4 sept. 2008 à 10:11
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
- 10 sept. 2008 à 09:36
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

7 réponses

sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2
8 sept. 2008 à 14:47
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
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
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2
4 sept. 2008 à 13:18
bonjour,

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

Merci
0
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

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
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
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2
4 sept. 2008 à 15:28
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
in2ni > sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014

4 sept. 2008 à 19:05
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
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2 > in2ni
5 sept. 2008 à 15:28
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
in2ni > sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014

8 sept. 2008 à 10:38
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
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2 > in2ni
8 sept. 2008 à 16:57
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
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
sbouli
Messages postés
200
Date d'inscription
jeudi 20 décembre 2007
Statut
Membre
Dernière intervention
14 août 2014
2
10 sept. 2008 à 09:36
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