encoding - tecnicas - ¿Qué es la codificación de caracteres y por qué debería molestarme con ella?
enojo psicologia (3)
Estoy bastante confundido sobre el concepto de codificación de caracteres .
¿Qué es Unicode, GBK, etc.? ¿Cómo los usa un lenguaje de programación?
¿Debo molestarme en saber sobre ellos? ¿Hay una manera más simple o más rápida de programar sin tener que preocuparme por ellos?
ASCII es fundamental
Originalmente, 1 carácter siempre se almacenaba como 1 byte. Un byte (8 bits) tiene el potencial de distinguir 256 valores posibles. Pero, de hecho, solo se usaron los primeros 7 bits . Entonces solo se definieron 128 caracteres. Este conjunto se conoce como el juego de caracteres ASCII .
-
0x00
-0x1F
contienen códigos de dirección (p. Ej., CR, LF, STX, ETX, EOT, BEL, ...) -
0x20
-0x40
contienen números y signos de puntuación -
0x41
-0x7F
contienen en su mayoría caracteres alfabéticos -
0x80
-0xFF
el 8º bit = indefinido.
Francés, alemán y muchos otros idiomas necesitan caracteres adicionales. (por ejemplo à, é, ç, ô, ...
) que no estaban disponibles en el juego de caracteres ASCII. Entonces usaron el 8vo bit para definir sus personajes. Esto es lo que se conoce como " ASCII extendido ".
El problema es que el bit adicional 1 no tiene capacidad suficiente para cubrir todos los idiomas del mundo. Entonces, cada región tiene su propia variante ASCII. Hay muchas codificaciones ASCII extendidas ( latin-1
es muy popular).
Pregunta popular: "¿Es ASCII un conjunto de caracteres o es una codificación" ? ASCII
es un conjunto de caracteres. Sin embargo, en la programación, el charset
y la encoding
se usan ampliamente como sinónimos. Si quiero referirme a una codificación que solo contiene los caracteres ASCII y nada más (el 8vo bit es siempre 0): eso es US-ASCII
.
Unicode va un paso más allá
Unicode también es un conjunto de caracteres (no una codificación) . Utiliza los mismos caracteres como el estándar ASCII, pero amplía la lista con caracteres adicionales, lo que le da a cada carácter un punto de código en formato u+xxxx
. Tiene la ambición de contener todos los personajes (e iconos populares) utilizados en todo el mundo.
UTF-8, UTF-16 y UTF-32 son codificaciones que aplican la tabla de caracteres Unicode. Pero cada uno tiene una forma ligeramente diferente de cómo codificarlos. UTF-8 solo usará 1 byte al codificar un carácter ASCII, dando el mismo resultado que cualquier otra codificación ASCII. Pero para otros personajes, usará el primer bit para indicar que seguirá un segundo byte.
GBK es una codificación, que al igual que UTF-8 usa múltiples bytes. El primer byte sigue el estándar ASCII, por lo que solo se utilizan 7 bits. El octavo bit se usa para indicar la presencia de un segundo byte, que se usa para representar aproximadamente 22,000 caracteres chinos. Pero una diferencia importante es que esto no respeta el conjunto de caracteres Unicode .
Tipos de Mime
Los tipos MIME también se confunden a menudo con codificaciones.
No hay una forma sencilla de decodificar un archivo. Hubiera sido ideal si todos los archivos contuvieran un prefijo para indicar en qué codificación estaban almacenados sus datos. Al final, le corresponde a la aplicación (o su desarrollador) determinar una codificación (por ejemplo, US-ASCII
, UTF-8
, algunos sistema por defecto ...).
Al enviar datos a través de internet, existe el mismo problema. Afortunadamente, algunos protocolos como HTTP usan declaraciones tipo mime para especificar qué tipo de datos y juego de caracteres usan los datos . Un encabezado HTTP típico contiene esto:
Content-Type: text/html; charset=utf-8
Pero para text/xml
eso sería inútil (incluso se ignorará un parámetro de conjunto de caracteres). Los analizadores XML en general leerán la primera línea del archivo, buscando la etiqueta <?xml encoding=...
Si está allí, entonces volverán a abrir el archivo usando esa codificación.
El mismo problema existe al enviar correos electrónicos . Un correo electrónico puede contener un mensaje html o simplemente texto sin formato.
Atajos
En el caso de Java (y muchos otros lenguajes de programación), además de los peligros de las codificaciones, también existe la complejidad de convertir bytes y enteros en caracteres porque su contenido se almacena en diferentes rangos.
- un byte se almacena como un byte firmado (rango:
-128
a127
). - el tipo de caracteres en Java se almacena en 2 bytes sin firmar (rango:
0
-65535
) - una secuencia devuelve un número entero en el rango
-1
a255
.
Si sabe que sus datos solo contienen valores ASCII. Luego, con la habilidad adecuada, puede analizar sus datos de bytes a caracteres o envolverlos inmediatamente en Cadenas.
// the -1 indicates that there is no data
int input = stream.read();
if (input == -1) throw new EOFException();
// bytes must be made positive first.
byte myByte = (byte) input;
int unsignedInteger = myByte & 0xFF;
char ascii = (char)(unsignedInteger);
El acceso directo en Java es usar lectores y escritores y especificar la codificación cuando los crea.
// wrap your stream in a reader.
// specify the encoding
// The reader will decode the data for you
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
Como se explicó anteriormente para los archivos XML, no importa mucho, ya que cualquier marcador decente DOM o JAXB comprobará un atributo de codificación.
Conjuntos de personajes vs Codificaciones
Para aquellos que aún no lo entienden
Aquí hay un ejemplo extremo que ilustra que un juego de caracteres es solo un mapeo primitivo, mientras que una codificación es más como un algoritmo que dicta cómo los caracteres deben traducirse a bytes. Sin embargo, tenga en cuenta cómo internamente la "codificación loca" usa el "juego de caracteres loco".
Esta relación es exactamente como la relación que UTF-8 tiene para unicodear. Unicode es solo un conjunto de caracteres, pero es UTF-8 el que define cómo se debe traducir este conjunto de caracteres a bytes. Similary UTF-16 también usa unicode, pero lo traduce de una manera totalmente diferente. UTF-8 y UTF-16 son codificaciones basadas en el conjunto de caracteres Unicode.
(Tenga en cuenta que estoy usando algunos de estos términos de manera general / coloquial para una explicación más simple que todavía golpea los puntos clave).
Un byte solo puede tener 256 valores distintos, que son 8 bits.
Dado que hay conjuntos de caracteres con más de 256 caracteres en el conjunto de caracteres, no se puede, en general, decir simplemente que cada carácter es un byte.
Por lo tanto, debe haber asignaciones que describan cómo convertir cada carácter en un conjunto de caracteres en una secuencia de bytes. Algunos caracteres pueden asignarse a un solo byte, pero otros deberán asignarse a varios bytes.
Esas asignaciones son codificaciones, porque te están diciendo cómo codificar caracteres en secuencias de bytes.
En cuanto a Unicode, en un nivel muy alto, Unicode es un intento de asignar un número único y único a cada personaje. Obviamente ese número tiene que ser algo más ancho que un byte ya que hay más de 256 caracteres :) Java usa una versión de Unicode donde a cada personaje se le asigna un valor de 16 bits (y es por eso que los caracteres Java son de 16 bits de ancho y tienen un entero valores de 0 a 65535). Cuando obtiene la representación de bytes de un carácter Java, debe indicarle a la JVM la codificación que desea utilizar para que sepa cómo elegir la secuencia de bytes para el carácter.
La codificación de caracteres es lo que usa para resolver el problema de escribir software para alguien que usa un idioma diferente del suyo.
No sabes cómo son los personajes y cómo están ordenados. Por lo tanto, no sabes cómo se verán las cadenas en este nuevo idioma en binario y, francamente, no te importa.
Lo que sí tiene es una forma de traducir cadenas del idioma que habla al idioma que habla (por ejemplo, un traductor). Ahora necesita un sistema que sea capaz de representar ambos idiomas en binario sin conflictos. La codificación es ese sistema.
Es lo que le permite escribir software que funciona independientemente de la forma en que se representan los idiomas en binario.