2011-02-17 12 views
5

Necesito procesar una larga lista de cadenas cortas (la mayoría en ruso, pero cualquier otro idioma es posible, incluida la basura aleatoria de un gato que camina sobre el teclado).Detectar si una cadena estaba codificada en UTF-8

Algunas de estas cadenas se codificarán en UTF-8 dos veces.

Necesito detectar de forma fiable si una cadena dada tiene una codificación doble y corregirla. Debo hacer esto sin usar ninguna biblioteca externa, simplemente inspeccionando los bytes. La detección debe ser lo más rápido posible.

La pregunta es: ¿cómo detectar que una cadena dada fue codificada en UTF-8 dos veces?

Actualización:

cadenas originales están en UTF-8. Aquí está el código AS3 que lo hace la segunda codificación (por desgracia no tengo el control sobre el código de cliente, por lo que no se puede solucionar este problema):

private function toUTF8(s : String) : String { 
     var byteArray : ByteArray = new ByteArray(); 
     byteArray.writeUTFBytes(s); 
     byteArray.position = 0; 

     var res : String = ""; 

     while(byteArray.bytesAvailable){ 
      res += String.fromCharCode(byteArray.readUnsignedByte()); 
     } 

     return res; 
} 

myString = toUTF8(("" + myString).toLowerCase().substr(0, 64)); 

Nota toLowerCase() llamada. Tal vez esto puede ayudar?

+1

¿Qué quiere decir con doble codificado en UTF-8? ? –

+2

@Martin: FWIW, mi respuesta asume que significa tomar texto en Encoding X, transformarlo a UTF-8 bytes, luego tomar esos bytes, reinterpretarlos como Encoding X y transformarlos en bytes UTF-8. En otras palabras, qué sucede cuando interpreta incorrectamente un archivo UTF-8 como ISO-8859-1 (o lo que sea) y luego "lo convierte a UTF-8". –

+0

Bueno, el texto original estaba en UTF-8, y está codificado en UTF-8 una vez más por la biblioteca de clientes con errores. (Trataré de obtener más detalles sobre en qué codificación asumió la biblioteca el texto) –

Respuesta

4

En principio no se puede, especialmente teniendo en cuenta la basura del gato.

No dice cuál era la codificación original de caracteres de los datos antes de que fuera codificada en UTF-8 una o dos veces. Asumiré CP1251, (o al menos ese CP1251 es una de las posibilidades) porque es un caso bastante complicado.

Tome un carácter que no sea ASCII. UTF-8 lo codifica. Obtiene algunos bytes, y todos esos bytes son caracteres válidos en CP1251 a menos que uno de ellos sea 0x98, el único agujero en CP1251.

Por lo tanto, si convierte esos bytes de CP1251 a UTF-8, el resultado es exactamente el mismo que si hubiera codificado UTF-8 correctamente una cadena CP1251 formada por esos caracteres rusos. No hay forma de saber si el resultado es una doble codificación incorrecta de un carácter o una sola codificación correcta de 2 caracteres.

Si tiene algún control sobre los datos originales, puede poner una lista de materiales al comienzo. Luego, cuando vuelva a usted, inspeccione los bytes iniciales para ver si tiene una lista de materiales UTF-8 o el resultado de una doble codificación incorrecta de una lista de materiales. Pero supongo que probablemente no tengas ese tipo de control sobre el texto original.

En la práctica se puede adivinar - UTF-8 decodificación y luego:

(a) un vistazo a las frecuencias de caracteres, par de caracteres frecuencias, número de caracteres no imprimibles. Esto podría permitirle declarar tentativamente una tontería y, por lo tanto, posiblemente una doble codificación. Con suficiente cantidad de caracteres no imprimibles, puede ser tan absurdo que no podría escribirlo de manera realista ni siquiera machacando el teclado, a menos que su tecla ALT esté bloqueada.

(b) intente la segunda decodificación. Es decir, a partir de los puntos de código Unicode que obtuvo decodificando sus datos UTF-8, primero codifíquelos en CP1251 (o lo que sea) y luego decodifique el resultado de UTF-8. Si cualquiera de los pasos falla (debido a secuencias inválidas de bytes), entonces definitivamente no estaba codificado en doble, al menos no usando CP1251 como la interpretación defectuosa.

Esto es más o menos lo que debe hacer si tiene algunos bytes que podrían ser UTF-8 o podrían ser CP1251, y usted no sabe cuál.

Obtendrá algunos resultados positivos falsos para cat-basura indistinguible de datos codificados doblemente, y tal vez unos pocos falsos negativos para datos codificados doblemente pero que después de la primera codificación por casualidad aún se veía como Ruso.

Si la codificación original tiene más agujeros que CP1251, tendrá menos falsos negativos.

Las codificaciones de caracteres son difíciles.

+0

Tiene razón, no tengo control sobre las cadenas originales. Pero actualicé la pregunta con más información, tal vez esto ayude. –

2

Aquí hay un algoritmo de PHP que funcionó para mí.

Es mejor corregir sus datos, pero si no puede He aquí un truco:

if (mb_detect_encoding(utf8_decode($value)) === 'UTF-8') { 
    // Double encoded, or bad encoding 
    $value = utf8_decode($value); 
} 

$value = \ForceUTF8\Encoding::toUTF8($value); 

La biblioteca que estoy usando es: https://github.com/neitanod/forceutf8/

+1

esto funciona, en realidad, bastante bien – bhelm

Cuestiones relacionadas