2009-06-08 22 views
9

Considere el siguiente código:Manejo de valores de sustitución Unicode en cadenas de Java

byte aBytes[] = { (byte)0xff,0x01,0,0, 
        (byte)0xd9,(byte)0x65, 
        (byte)0x03,(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, 
        (byte)0x17,(byte)0x33, (byte)0x74, (byte)0x6f, 
        0, 1, 2, 3, 4, 5, 
        0 }; 
String sCompressedBytes = new String(aBytes, "UTF-16"); 
for (int i=0; i<sCompressedBytes.length; i++) { 
    System.out.println(Integer.toHexString(sCompressedBytes.codePointAt(i))); 
} 

Obtiene el siguiente resultado incorrecto:

ff01, 0, fffd, 506, 717, 3374, 6f00, 102, 304, 500. 

Sin embargo, si el 0xd9 en los datos de entrada se cambia a 0x9d, a continuación, se obtiene la siguiente salida correcta:

ff01, 0, 9d65, 304, 506, 717, 3374, 6f00, 102, 304, 500. 

I reali ze que la funcionalidad se debe al hecho de que el byte 0xd9 es un marcador Unicode de alto sustituto.

Pregunta: ¿Hay alguna manera de alimentar, identificar y extraer bytes suplentes (0xd800 en 0xdfff) en una cadena Java Unicode?
Gracias

Respuesta

4

¿Hay una manera de alimentar, identificar y extraer bytes sustitutas (0xd800 a 0xdfff) en una cadena Unicode de Java ?

Simplemente porque nadie lo ha mencionado, señalaré que la clase Character incluye los métodos para trabajar con pares sustitutos. P.ej. isHighSurrogate(char), codePointAt(CharSequence, int) y toChars(int). Me doy cuenta de que esto es además del punto del problema planteado.

new String(aBytes, "UTF-16"); 

Esta es una operación de decodificación que transformará los datos de entrada.Estoy bastante seguro de que no es legal porque la operación de decodificación elegida requiere que la entrada comience con 0xfe 0xff o 0xff 0xfe (byte order mark). Además, no todos los valores de bytes posibles se pueden decodificar correctamente porque UTF-16 es variable width encoding.

Si querían una transformación simétrica de bytes arbitrarios en cadena y la espalda, que está mejor con un niño de 8 bits, la codificación de un solo byte, porque cada valor de byte es un carácter válido:

Charset iso8859_15 = Charset.forName("ISO-8859-15"); 
byte[] data = new byte[256]; 
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { 
    data[i - Byte.MIN_VALUE] = (byte) i; 
} 
String asString = new String(data, iso8859_15); 
byte[] encoded = asString.getBytes(iso8859_15); 
System.out.println(Arrays.equals(data, encoded)); 

Nota: la cantidad de caracteres va a ser igual a la cantidad de bytes (duplicando el tamaño de los datos); la cadena resultante no necesariamente será imprimible (que contiene, como podría ser, un bunch of control characters).

Soy with Jon, aunque poner secuencias de bytes arbitrarias en cadenas de Java es casi siempre una mala idea.

10

EDIT: Esto se refiere a la cuestión del comentario

Si desea codificar datos binarios arbitrarios en una cadena, debe no utilizar una codificación de texto normal. No tiene texto válido en esa codificación; solo tiene datos binarios arbitrarios.

Base64 es el camino a seguir aquí. No hay soporte de base64 directamente en Java (en una clase pública, de todos modos), pero hay varias bibliotecas de terceros que puede usar, como the one in the Apache Commons Codec library.

Sí, base64 aumentará el tamaño de los datos, pero le permitirá decodificarlo más tarde sin perder información.

EDIT: Esto se refiere a la pregunta original

Creo que el problema es que no se ha especificado un sustituto adecuado par. Debería especificar los bytes que representan un sustituto bajo y luego un sustituto alto. Después de eso, debería poder agregar el punto de código apropiado. En tu caso, has dado un bajo sustituto por sí mismo.

Aquí es código para demostrar esto:

public class Test 
{ 
    public static void main(String[] args) 
     throws Exception // Just for simplicity 
    { 
     byte[] data = 
     { 
      0, 0x41, // A 
      (byte) 0xD8, 1, // High surrogate 
      (byte) 0xDC, 2, // Low surrogate 
      0, 0x42, // B 
     }; 

     String text = new String(data, "UTF-16"); 

     System.out.printf("%x\r\n", text.codePointAt(0)); 
     System.out.printf("%x\r\n", text.codePointAt(1)); 
     // Code point at 2 is part of the surrogate pair 
     System.out.printf("%x\r\n", text.codePointAt(3));  
    } 
} 

Salida:

41 
10402 
42 
+0

Creo que tienes razón. Acababa de llegar a la misma conclusión, pero volví a ver si alguien más conocedor ya había respondido. –

+0

simplemente insertando "(byte) 0xDC, (byte) 0xEF," rendimientos "FF01 694ef dcef ...", que es como debe ser. –

+0

Gracias por sus respuestas. Pero, el problema no se trata de incrustar personajes sustitutos. El requisito es alimentar cualquier secuencia de bytes arbitraria (que se obtiene a partir de la compresión) en una cadena de Java y leerla nuevamente como una secuencia de bytes equivalente. –

Cuestiones relacionadas