Informática

Anuncio
Codificación
de Caracteres
Informática
Ing. Mariano D'Agostino (y otros)
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
El siguiente material es una obra derivada creada por Mariano D'Agostino de los artículos
•
Juegos de Caracteres I: ASCII e ISO-8859 Creado por Jose Ignacio Galarza.
http://sysvar.net/es/juegos-de-caracteres-i-ascii-e-iso-8859
•
Juegos de Caracteres II: Unicode y UTF Creado por Jose Ignacio Galarza.
http://sysvar.net/es/juegos-caracteres-ii-unicode-y-utf
•
ASCII, Unicode, UTF-8 y la Iñtërnâçiônàlizæçiøn - parte I Creado por Juan Pablo Aqueveque.
http://v3.juque.cl/weblog/2006/01/25/ascii-unicode-utf8-y-la-iatarnaaianalizaaian-parte-i.html
•
ASCII, Unicode, UTF-8 y la Iñtërnâçiônàlizæçiøn - parte II Creado por Juan Pablo Aqueveque.
http://v3.juque.cl/weblog//2006/04/02/ascii-unicode-utf8-y-la-iatarnaaianalizaaian-parte-ii.html
•
Foto de la caratula adaptada de https://www.flickr.com/photos/jbcurio/4891501660
Y está licenciado bajo licencia Creative Commons (BY-SA). [http://creativecommons.org/licenses/bysa/4.0/deed.es].
Introducción
Es probable que navegando por Internet, o al recibir un correo electrónico algunos
acentos, las letras eñe o algunos signos de exclamación se vean de forma extraña,
como símbolos sin sentido.
Esto se lo podemos agradecer a los juegos de caracteres y a la historia que han tenido
durante las últimas décadas.
¿Juegos de caracteres?
Toda la información que vemos en nuestro computadora está guardada de forma
binaria. Ristras de 0's y 1's que representan nuestra información. Las cadenas de
caracteres no son una excepción. Hay muchas maneras de representar caracteres,
siendo la más sencilla el identificar cada letra mediante un código numérico. Y vamos a
considerar como carácter cada uno de los símbolos que existen en el alfabeto,
incluidas mayúsculas y minúsculas. Es decir, el carácter a no es el mismo que el
carácter A.
1
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
Y es el sistema operativo, mediante este código, el que sabe como dibujar el respectivo
carácter... ¿Pero quién decide que código corresponde a cada uno? Y es con esta
pregunta con la que empieza nuestro caos.
Veamos algunas definiciones:
•
Un caracter es el componente más pequeño de un lenguaje escrito y además
posee un valor semántico. Ejemplos de caracter: “1”, “.”, “A” “ 纯”.
•
Un conjunto de caracteres es un grupo de caracteres sin ningún valor numérico
asociado. Ejemplos de conjunto de caracteres puede ser el alfabeto Español o el
Cirílico (usado en Rusia y Bulgaria).
•
Un conjunto de caracteres codificados es un grupo de caracteres asociados a un
valor escalar. Ejemplo la letra “A” mayúscula, que según la tabla ASCII tiene el
valor 65.
Una computadora funciona en base a cambios eléctricos: prendido y apagado, sí y no;
un estado binario que es representado con 1's y 0's respectivamente, absolutamente
todo es representado en ceros y unos dentro de estas máquinas: un mp3, una
fotografía digital, un texto, etcétera. Quedemos con el texto por un momento; cuando
escribimos uno igualmente queda almacenado en el computador como una hilera de 0's
y 1's. Supongamos que escribimos un texto con la palabra: Hola, su representación
binaria sería:
Binario
Caracter
-----------------1001000
|
H
1101111
|
o
1101100
|
l
1100001
|
a
Uno podría preguntarse, ¿Cómo es que el binario 1001000 representa el caracter “H”?,
¿perfectamente pudo haber sido el 1110011?, para responder estas preguntas
debemos retroceder un poco al al pasado.
2
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
El mundo de la informática tuvo su origen en Los Estados Unidos, allá por 1963 era
necesario establecer un estándar para el intercambio de información, es así como se
creó el conocido código ASCII (aunque también es conocido como US-ASCII), el cual
define un conjunto de caracteres asociados a un valor escalar, según esta tabla el
caracter “H” se representará como 1001000
“¡Fantástico!, ya tenemos un estándar para el intercambio de información para nuestro
idioma” —decían los patriarcas de la informática, nótese “para nuestro idioma”.
Correcto, el estándar ASCII definía un conjunto de caracteres sólo para el habla
inglesa, es decir, su alfabeto (que por lo demás es bastante simple), números, signos
de puntuación, caracteres de control. La suma total de caracteres va desde 0 al 127, en
total 128.
US-ASCII - desde el 0 al 127.
* | 0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
-------------------------------------------------------------0 | NUL SOH STX ETX EOT ENQ ACK BEL BS TAB LF
VT
FF CR SO SI
1 | DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2 | (1)
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
3 | 0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
4 | @
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
5 | P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
6 | `
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
7 | p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL
(1): caracter de espacio
Por comodidad y convención de ahora en adelante ya no nos vamos a referir a nuestro
caracter “H” con su representación binaria, ahora nos referiremos a él en su notación
ASCII hexadecimal, es decir 0x48 (fila 4, columna 8 de la tabla). El intervalo 0x00 a
0x1F son abreviaturas en inglés de: nulo, comienzo de cabecera, comienzo de texto, fin
de texto...etc. Este grupo también es llamado no imprimible dado que todos son
caracteres de control. Curiosidad: el caracter ASCII 0x7 por ejemplo es el caracter que
hace que nuestro computador haga “bip”. La tabla completa, junto con otros interesante
3
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
datos puedes verla en [wikipedia. http://es.wikipedia.org/wiki/ASCII).
Un bit es un dígito en el sistema de numeración con base dos, el código binario. El dos
(2) binario se representa con dos bits 10, el cuatro (4) binario con tres 100. Se
denomina nibble a un grupo de 4 bits, con cuatro bits podemos representar hasta 24 =
16 valores diferentes, un grupo de 8 bits se denomina octeto y se pueden representar
hasta 28 = 256 valores distintos. Un octeto es siempre fijo (8 bits), mientras que un byte
es un grupo de 8 bits también pero no siempre ha sido así, cuando la informática
estaba en pañales un byte podía contener 6,7,8 o 9 bits. Pero estamos hablando de la
prehistoria, hoy en día para la inmensa mayoría de los sistemas un grupo de 8 bits es
denominado como un byte. El concepto que debes retener es: que un byte es la unidad
básica de almacenamiento de información.
ASCII
La mayor parte de los computadores direccionan a nivel de byte, y esto de la
informática nació en una época en la que el almacenamiento era algo costoso y escaso
por lo que la idea de que cada carácter ocupase sólo un byte era algo bastante
razonable.
De esos 8 bits (8 bits == 1 Byte) decidieron usar 7 para representar todos los
caracteres que ellos creían eran necesarios para cualquier persona. En este grupo nos
encontramos aparte del alfabeto inglés, distintos símbolos de puntuación (interrogación,
coma, exclamación…) y por último, caracteres de control no imprimibles como el salto
de línea, el tabulador, o el valor NULL, el cual como muchos sabrán, tiene el valor 0x00
(los siete bits a cero). Podés ver que valor tiene exactamente cada carácter en la
Wikipedia.
Por ejemplo, y según lo que acabamos de ver, si escribimos en un archivo la cadena
Hola! (guardándolo en ASCII), y abrimos ese fichero con algún lector binario, veremos
que el contenido es el siguiente:
01001000 01101111 01101100 01100001 00100001
4
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
H
o
l
a
!
Pero hemos dicho que se direcciona a nivel de byte así que… ¿qué pasa con el bit
número 8? Pues que sobra, no les hizo falta, así que decidieron usarlo como bit de
paridad para comprobar que no había corrupción en los datos (a la hora de mandar el
carácter por la red por ejemplo).
Y todo fue muy bonito… hasta que al resto de la humanidad (de habla no inglesa) se le
dio por probar aquello de las computadoras, y vió que, por ejemplo, no podía escribir
nuestra preciosa ñ. El estándar ASCII no servía.
ISO-8859-1
Cuando se planteó representar caracteres de otros alfabetos se vio claramente que ese
octavo bit de ASCII que no se usaba era una oportunidad fantástica para ampliar con
128 nuevos códigos el set ya existente.
Por poner un ejemplo, uno de estos juegos que se crearon es el llamado ISO-8859-1,
que es un set creado con el propósito de representar los carácteres de la mayor parte
de los alfabetos derivados del latín que hay. De esta manera, en esos 128 carácteres
extras tenemos letras de nuestro idioma, francés, griego… Por poner un ejemplo, la
palabra año se representa de la siguiente manera:
01100001 11110001 01101111
a
ñ
o
El problema de todo esto es que lo de usar el octavo bit de ASCII (notar en que la letra
ñ es la única que tiene un 1 en el octavo bit en el ejemplo anterior) es algo que se le
ocurrió a mucha gente al mismo tiempo, creándose una infinidad de juegos de
caracteres que usaban los siete primeros bits de la misma forma que ASCII (por lo que
eran compatible con este) y usaban el octavo para representar los caracteres que les
interesaba. Todos estos sets se dicen que son ASCII extendido.
Y con esto de tener una infinidad de juegos distintos surge un enorme problema, y es
5
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
que un texto escrito en un juego es totalmente incompatible y de hecho se puede
ver de forma totalmente ininteligible en un ordenador que tuviese otro distinto.
Por ejemplo, la misma sucesión de bits que en ISO-8859-1 nos da la palabra año, en
Windows-1253 (una codificación muy usada en Grecia) nos da la palabra aρo
(atención, no es un carácter p normal)
01100001 11110001 01101111
a
ρ
o
Aquí tenemos el primer origen de los caracteres extraños en nuestros ficheros. Y por
esta razón solo los vemos en los caracteres acentuados. Los normales, como son
compartidos por ASCII normal, son representados de igual manera en todas las
codificaciones existentes. Son los caracteres de ASCII extendido los que, si los vemos
desde un set distinto al que fue creado, provocan que el texto se vea totalmente
distinto.
Así pues, estaba claro que esta situación había que arreglarla. Y un comité se puso
manos a la obra, creando lo que ahora conocemos como Unicode. La que las uniría a
todas. Un set que promete incluir todos los posibles carácteres que existen en nuestro
planeta.
Unicode
Este estándar fue desarrollado por la UTC y tiene como particularidad que no es un
juego de caracteres. La primera tarea para representar los distintos caracteres es
asignarles un código numérico. Pues esto es exactamente lo que hace Unicode, y nada
más. Básicamente es el estándar encargado de asignarle un código numérico a cada
uno de los distintos caracteres representables sobre la faz de la tierra.
A la hora de referirnos a un carácter unicode vamos a usar el siguiente formato:
U+XXXX, siendo las X el código numérico del respectivo carácter (en base
hexadecimal). Por poner un ejemplo, el carácter e se representa mediante la secuencia
U+0065. Por poner otro ejemplo, el carácter de la carita sonriente ☺ posee el código
6
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
Unicode U+263A y el símbolo de reciclaje ♻ posee el código U+2672. Se pueden ver
todos los símbolos unicode en la siguiente web: http://unicode-table.com/es/
El lector avispado se habrá dado cuenta de que el carácter e usa el mismo código
numérico en ASCII y en Unicode. Y es que esta es una de las grandes cualidades de
Unicode, los primeros caracteres son los ASCII, por lo que igual que en el caso anterior,
tenemos que este set, en sus primeros valores al menos, es compatible con el estándar
de facto anterior.
Pero nos faltan muchos actores aún en la película. Como hemos dicho, Unicode no es
un juego de caracteres, por lo que en el estándar no hay ninguna referencia a como se
han de representar los caracteres de manera binaria (dentro de una computadora). Y
esta tarea no es tan sencilla como hasta ahora, debido a que Unicode contiene
muchísimos más caracteres de los que caben en un byte. Y es aquí donde aparecen
las tres codificaciones más usadas en la actualidad: UTF-8, UTF-16 y UTF-32. Vamos a
ver como funcionan en orden inverso, ya que es la forma más simple de ver sus
ventajas y desventajas.
UTF-32
Esta es la variante más sencilla que hay. Los caracteres se guardan en 32bits (4
Bytes), por lo que la correspondencia entre el código numérico Unicode y la
representación binaria en esta codificación es directa. Es decir, el carácter Unicode e,
que como vimos antes tiene el código U+00000065 (puedo añadir todos los ceros que
quiera delante) se representará de la siguiente manera:
00000000 00000000 00000000 01100101
e
Sí, un sólo carácter ocupa toda esa cantidad de espacio. Cada carácter ocupará 4
veces más (1 Byte contra 4 Bytes). Al hecho de que es un derroche de espacio
7
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
sangrante hay que sumarle que en un gran porcentaje de los casos la información que
circula es de los primeros 127 caracteres, es decir, de la tabla ASCII inicial, por lo que
estaremos mandando bytes de ceros a mansalva, ya que los caracteres ASCII se
codificarán siempre con los tres primeros bytes a cero, y el último con el código del
carácter en cuestión.
Las mentes pensantes vieron que esto no podía ser por lo que idearon otras formas
más óptimas de codificar Unicode. Decir que, por esta razón, muy pocas
aplicaciones/sistemas usan esta codificación para representar Unicode.
UTF-16
Algunas personas se dieron cuenta de que la inmensa mayoría de la humanidad usa un
subconjunto de lo que ellos codificaron en Unicode, y que este subconjunto estaba
situado en la primera mitad de la tabla. A este subconjunto lo llamaron plano básico
multilingüe (o BMP de sus siglas en inglés). El BMP puede representarse mediante 2
Bytes, por lo que esta codificación usa de forma fija 2 Bytes para poder representar
todos los caracteres de este subconjunto (2 Bytes = 16 bits).
Es decir, si se toma un carácter que esté desde el U+0000 al U+FFFF su
representación binaria será exacta (tal como lo era en UTF-32 pero con 2 Bytes de
ceros menos, ya que ahora los caracteres ocupan la mitad). Por poner el mismo
ejemplo de antes, ahora el carácter e se representaría con la siguiente secuencia:
00000000 01100101 e
Como podemos ver, es una mejora enorme con respecto a UTF-32. Pero, ¿y qué pasa
con los caracteres más allá de U+FFFF? Pues que también se pueden codificar, pero
no de forma directa. En este caso UTF-16 empleará 2 pares de 2 Bytes (es decir, que
ocupará exactamente lo mismo que en UTF-32). Mediante estos dos pares y una serie
de transformaciones se podrán codificar estos bytes. La explicación de como lo hace
queda fuera de este texto, ya que es algo intrincada. El UTF-16 es más que el UTF-32
en la actualidad.
8
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
Pero aun así este sistema sigue teniendo varios problemas. El primero, que seguimos
mandando muchos ceros debido a que toda la tabla ASCII tiene el primer byte a cero
siempre. El segundo, que el sistema para codificar bytes más allá del U+FFFF es
bastante complicado. Tercero, que todos los documentos escritos hasta la fecha se
dejarían de ver bien. UTF-16 (y 32) no son compatibles con ASCII debido a que los
caracteres ocupan un número distintos de bytes, a pesar de que el código numérico
sea equivalente. Para solucionar estos problemas, tenemos nuestra última codificación.
UTF-8
Este sistema de codificación está realmente bien pensado. Es un sistema dinámico, en
cuanto a que a diferencia de los dos anteriores, no ocupa una cantidad de bytes fijo. En
su lugar, usa un formato predefinido a la hora de codificar los caracteres, y en base a
este formato ese carácter ocupará más o menos, siendo el rango entre 1Byte y 6Bytes
(sí, puede llegar a ocupar más que UTF-32 para los caracteres más lejanos de la tabla
Unicode.)
Rango Unicode
|
UTF-8 secuencia de octetos
(hexadecimal)
|
(binario)
--------------------+--------------------------------------------0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
0020 0000-03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
0400 0000-7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
Este sistema funciona de manera muy simple. En base al código numérico unicode, el
carácter ocupará uno o más bytes. Para indicar esto, el formato de los bytes será
representativo de cuantos bytes ocupa. Esto que parece muy complicado es muy
sencillo de ver con la tabla anterior . La primera columna indica el último código
9
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
numérico Unicode que entra en ese grupo, y las siguientes columnas indican como se
codifica cada uno de los bytes UTF-8. Los valores numéricos son fijos, y gracias a que
lo son, dependiendo de como empiece el primer byte se puede saber cuantos bytes
ocupa el carácter. Por otra parte, los valores que tienen una X se rellenan con el código
numérico Unicode del carácter que queramos codificar.
Veamos un ejemplo completo.
Tomemos el caracter H (Letra "H" latina mayúscula). Su punto de código (Unicode)
es el U+0048, 0x48 es menor que 0x7F por lo tanto tenemos que leer de la primera fila.
El binario del hexadecimal 0x48 es b1001000, por lo tanto el punto de código U+0048
se guardará en disco u/o memoria como b1000001. Toda la tabla US-ASCII, es decir,
aquellos 127 caracteres son exactamente los mismo en UTF-8, tienen la misma
representación escalar; con eso preservamos la compatibilidad hacia atrás.
Caracter a (Letra latina "a" minúscula) Punto de código U+0061. 0x61 es menor que
0x7F por lo tanto será codificado con un byte. Binario : 1100001 . Éste segundo
ejemplo también coincide con la representación binaria de la letra "a" según el juego de
caracteres US-ASCII. Hasta el momento tenemos perfecta compatibilidad.
Tomemos el caracter Ñ (letra "Ñ" latina mayúscula). Punto de código : U+00D1
0xD1 > 0x7F, por lo tanto NO corresponde al primer rango 0xD1 < 0x7FF, rango
correspondiente a la segunda fila. 0xD1 = 11010001 Según la tabla se utilizarán dos
bytes para representar la "Ñ", es así como 11010001 se transformará en: 11000011
10010001, su equivalente hexadecimal es 0xc3 y 0x91 respectivamente.
La palabra año en UTF-8 se codifica entonces como 61 c3 b1 6f donde 61 representa
la letra 'a'. c3 b1 representa la letra ñ y 6f representa el caracter 'o'.
¿Por qué seguimos viendo webs con problemas de codificación?
La pregunta que surge finalmente es, ¿Cuál es la razón por la cual seguimos viendo
sitios webs o emails con problemas de codificación?
10
MANIPULACIÓN Y PRESERVACIÓN DE DATOS
TÉCNICO EN INFORMÁTICA PROFESIONAL Y PERSONAL
La respuesta a esta pregunta está relacionada con alguna instrucciones que se definen
en el encabezado de una página web. Por ejemplo la instrucción
<meta charset="utf-8">
Le indicará al navegador que intente utilizar la codificación UTF-8 al dibujar la página
en el navegador. El problema es que si el archivo .html o la configuración del servidor
que genera la página está definido para usar otro tipo de juego de caracteres, se verán
los típicos símbolos � que indican que el navegador no supo como dibujar ese
caracter en la configuración especificada.
Para solucionar este problema lo que se busca es que tanto el servidor, como la
etiqueta "meta charset" estén configuradas para utilizar el mismo sistema de
codificación.
11
Descargar