Todo eso es parte de la codificación UTF8 (que es solo un esquema de codificación para Unicode).
El tamaño puede averiguado mediante el examen del primer byte de la siguiente manera:
- si comienza con el patrón de bits
"10" (0x80-0xbf)
, no es el primer byte de una secuencia y se debe realizar copias de seguridad hasta que encuentre el comienzo, cualquier byte que comience con "0" o "11" (gracias a Jeffrey Hantin por señalarlo en los comentarios).
- si comienza con el patrón de bits
"0" (0x00-0x7f)
, es de 1 byte.
- si comienza con el patrón de bits
"110" (0xc0-0xdf)
, son 2 bytes.
- si comienza con el patrón de bits
"1110" (0xe0-0xef)
, es de 3 bytes.
- si comienza con el patrón de bits
"11110" (0xf0-0xf7)
, es de 4 bytes.
Voy a duplicar la tabla que muestra esto, pero el original está en la página de Wikipedia UTF8 here.
+----------------+----------+----------+----------+----------+
| Unicode | Byte 1 | Byte 2 | Byte 3 | Byte 4 |
+----------------+----------+----------+----------+----------+
| U+0000-007F | 0xxxxxxx | | | |
| U+0080-07FF | 110yyyxx | 10xxxxxx | | |
| U+0800-FFFF | 1110yyyy | 10yyyyxx | 10xxxxxx | |
| U+10000-10FFFF | 11110zzz | 10zzyyyy | 10yyyyxx | 10xxxxxx |
+----------------+----------+----------+----------+----------+
caracteres UNICODE de la tabla anterior se construyen a partir de los bits:
000z-zzzz yyyy-yyyy xxxx-xxxx
donde se supone que los z
y y
bits a ser cero en el que no se les da. Algunos bytes son considerados ilegales como un byte de inicio ya que son bien:
- inútil: una secuencia de 2 bytes a partir de 0xc0 o 0xC1 en realidad le da un punto de código de menos de 0x80 que se puede representar mejor con un 1- secuencia de bytes.
- utilizado por RFC3629 para una secuencia de 4 bytes por encima de U + 10FFFF, o secuencias de 5 y 6 bytes. Estos son los bytes 0xf5 a 0xfd.
- no utilizado: bytes 0xfe y 0xff.
Además, los bytes subsiguientes en una secuencia de múltiples bytes que no comienzan con los bits "10" también son ilegales.
Como ejemplo, considere la secuencia [0xf4,0x8a, 0xaf, 0x8d]. Esta es una secuencia de 4 bytes ya que el primer byte cae entre 0xf0 y 0xf7.
0xf4 0x8a 0xaf 0x8d
= 11110100 10001010 10101111 10001101
zzz zzyyyy yyyyxx xxxxxx
= 1 0000 1010 1011 1100 1101
z zzzz yyyy yyyy xxxx xxxx
= U+10ABCD
Para su consulta específica con el primer 0xE6 bytes (longitud = 3), la secuencia de bytes es:
0xe6 0xbe 0xb3
= 11100110 10111110 10110011
yyyy yyyyxx xxxxxx
= 01101111 10110011
yyyyyyyy xxxxxxxx
= U+6FB3
Si nos fijamos ese código hasta here, verá que es el que usted tenía en su pregunta: 澳.
Para mostrar cómo funciona la decodificación, volví a mis archivos para encontrar mi código de manejo UTF8.Tuve que modificarlo un poco para convertirlo en un programa completo y la codificación se eliminó (ya que la pregunta era sobre decodificación), así que espero no haber introducido ningún error del corte y pegado:
#include <stdio.h>
#include <string.h>
#define UTF8ERR_TOOSHORT -1
#define UTF8ERR_BADSTART -2
#define UTF8ERR_BADSUBSQ -3
typedef unsigned char uchar;
static int getUtf8 (uchar *pBytes, int *pLen) {
if (*pLen < 1) return UTF8ERR_TOOSHORT;
/* 1-byte sequence */
if (pBytes[0] <= 0x7f) {
*pLen = 1;
return pBytes[0];
}
/* Subsequent byte marker */
if (pBytes[0] <= 0xbf) return UTF8ERR_BADSTART;
/* 2-byte sequence */
if ((pBytes[0] == 0xc0) || (pBytes[0] == 0xc1)) return UTF8ERR_BADSTART;
if (pBytes[0] <= 0xdf) {
if (*pLen < 2) return UTF8ERR_TOOSHORT;
if ((pBytes[1] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
*pLen = 2;
return ((int)(pBytes[0] & 0x1f) << 6)
| (pBytes[1] & 0x3f);
}
/* 3-byte sequence */
if (pBytes[0] <= 0xef) {
if (*pLen < 3) return UTF8ERR_TOOSHORT;
if ((pBytes[1] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
if ((pBytes[2] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
*pLen = 3;
return ((int)(pBytes[0] & 0x0f) << 12)
| ((int)(pBytes[1] & 0x3f) << 6)
| (pBytes[2] & 0x3f);
}
/* 4-byte sequence */
if (pBytes[0] <= 0xf4) {
if (*pLen < 4) return UTF8ERR_TOOSHORT;
if ((pBytes[1] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
if ((pBytes[2] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
if ((pBytes[3] & 0xc0) != 0x80) return UTF8ERR_BADSUBSQ;
*pLen = 4;
return ((int)(pBytes[0] & 0x0f) << 18)
| ((int)(pBytes[1] & 0x3f) << 12)
| ((int)(pBytes[2] & 0x3f) << 6)
| (pBytes[3] & 0x3f);
}
return UTF8ERR_BADSTART;
}
static uchar htoc (char *h) {
uchar u = 0;
while (*h != '\0') {
if ((*h >= '0') && (*h <= '9'))
u = ((u & 0x0f) << 4) + *h - '0';
else
if ((*h >= 'a') && (*h <= 'f'))
u = ((u & 0x0f) << 4) + *h + 10 - 'a';
else
return 0;
h++;
}
return u;
}
int main (int argCount, char *argVar[]) {
int i;
uchar utf8[4];
int len = argCount - 1;
if (len != 4) {
printf ("Usage: utf8 <hex1> <hex2> <hex3> <hex4>\n");
return 1;
}
printf ("Input: (%d) %s %s %s %s\n",
len, argVar[1], argVar[2], argVar[3], argVar[4]);
for (i = 0; i < 4; i++)
utf8[i] = htoc (argVar[i+1]);
printf (" Becomes: (%d) %02x %02x %02x %02x\n",
len, utf8[0], utf8[1], utf8[2], utf8[3]);
if ((i = getUtf8 (&(utf8[0]), &len)) < 0)
printf ("Error %d\n", i);
else
printf (" Finally: U+%x, with length of %d\n", i, len);
return 0;
}
se puede ejecutar con su secuencia de bytes (necesitará 4 a fin de utilizar 0 para rellenar fuera) de la siguiente manera:
> utf8 f4 8a af 8d
Input: (4) f4 8a af 8d
Becomes: (4) f4 8a af 8d
Finally: U+10abcd, with length of 4
> utf8 e6 be b3 0
Input: (4) e6 be b3 0
Becomes: (4) e6 be b3 00
Finally: U+6fb3, with length of 3
> utf8 41 0 0 0
Input: (4) 41 0 0 0
Becomes: (4) 41 00 00 00
Finally: U+41, with length of 1
> utf8 87 0 0 0
Input: (4) 87 0 0 0
Becomes: (4) 87 00 00 00
Error -2
> utf8 f4 8a af ff
Input: (4) f4 8a af ff
Becomes: (4) f4 8a af ff
Error -3
> utf8 c4 80 0 0
Input: (4) c4 80 0 0
Becomes: (4) c4 80 00 00
Finally: U+100, with length of 2
Los dos bytes que ha resaltado en su editor hexadecimal son dos bytes de un carácter de tres bytes. – thomasrutter
Tenga en cuenta que la información de Joel está un poco desactualizada: UTF-8 usa un máximo de cuatro bytes por carácter, no seis. Originalmente fue diseñado para codificar un potencial de 2^31 caracteres, pero fue reducido en 2003 para manejar solo el rango cubierto por la definición formal de Unicode, U + 0000 a U + 10FFFF. –