Codificação de caracteres
Internamente, um computador só armazena e processa bytes, números inteiros entre 0 e 255. Não é possível armazenar diretamente textos, imagens, sons ou qualquer outra informação que não sejam bytes.
Para armazenar informações mais complexas que os bytes, é necessário codificar as mesmas, ou seja, transformá-las em sequências de bytes. Esta página discute as técnicas usadas para transformar as letras e símbolos de um texto em bytes, para poder armazená-lo e tratá-lo em um computador.
A figura a seguir mostra as etapas do tratamento de uma letra A
pelo computador: o hardware do teclado é responsável por converter a letra digitada em byte(s) na memória do computador; em seguida, o hardware do terminal converte esses bytes em uma representação gráfica na tela.
Algumas definições
- Caractere: é um símbolo da linguagem (letra, dígito ou sinal). Exemplos:
A i ç ë ¥ β ɣ 诶 😃 ✂
- Conjunto de caracteres (charset): é o conjunto de todos os caracteres suportados por um sistema ou por um padrão de codificação. Exemplo:
A-Z, a-z, 0-9, ! @ # $ % * ( ) ~ _ - + = { } [ ] | \ / < . ,
- Codificação (encoding): é a tradução entre os caracteres e seus respectivos valores numéricos em bytes. Exemplo,
A
→ 65.
Existem diversas codificações de caracteres; a seguir serão apresentadas as mais usuais.
A codificação ASCII
A codificação de caracteres mais antiga ainda em amplo uso é a ASCII (American Standard Code for Information Interchange), criada nos anos 1960 a partir de códigos de telegrafia. Sua última atualização ocorreu em 1986, mesmo assim é considerada uma codificação universal.
A codificação ASCII abrange o conjunto de caracteres da língua inglesa, sinais gráficos e alguns caracteres de controle (nova linha, tabulação, etc), num total de 128 caracteres. Cada caractere é codificado em um byte, mas ocupa somente 7 bits; o oitavo bit de cada byte era antigamente usado para verificação de paridade.
A codificação ASCII é definida através da famosa Tabela ASCII, que é dividida em duas partes:
- 0 - 31 e 127: caracteres de controle (newline, form feed, tab, etc), que dependem do terminal utilizado.
- 32 - 126: caracteres imprimíveis (A, B, C, …), independentes de terminal.
A codificação ASCII ainda é amplamente usada para codificação de textos puros em inglês, como códigos-fonte de programas, páginas HTML, arquivos de configuração, etc.
Code pages
A codificação ASCII não suporta caracteres acentuados (á é ñ ë) ou caracteres específicos de outras línguas, como ç ¥ β ɣ 诶 etc. Pode-se usar o oitavo bit de cada byte para associar caracteres aos valores acima de 127. Isso levou à criação de diversas tabelas ASCII estendidas para definir os símbolos de 128 a 255. Cada codificação é denominada uma code page; algumas das mais conhecidas são:
- CP-437: (code page 437), codificação usada nos primeiros PCs, com caracteres acentuados e gráficos simples (▒ ╝ ╦ ┼).
- Windows-1252: codificação usada em sistemas Windows mais antigos; é parte de um conjunto de codificações para diversas linguagens chamado Windows code pages.
- KOI8-R: cirílico russo (Код Обмена Информацией, 8 бит).
- BraSCII: português brasileiro, usada nos anos 1980-90.
- ISO-8859 : codificações da ISO para diversas línguas.
Codificações ISO-8859
Nos anos 1980, para para tentar organizar a profusão de codepages ASCII estendidas, a ISO propôs o conjunto de padrões ISO-8859, que define codificações ASCII estendidas para diversas linguagens, como por exemplo:
- ISO-8859-1: Europa ocidental (francês, espanhol, italiano, alemão, etc)
- ISO-8859-15: revisão do ISO-8859-1, contendo o € e outros símbolos
- ISO-8859-2: Europa central (Bósnio, Polonês, Croata, etc)
- ISO-8859-6: árabe simplificado
- ISO-8859-7: grego
As codificações ISO-8859 se tornaram um padrão mundial e ainda são amplamente usadas em muitos sistemas, sendo gradualmente substituída pela codificação Unicode em sistemas mais recentes. Elas são compatíveis com a codificação ASCII, pois representam cada caractere com somente um byte e respeitam as definições ASCII dos caracteres de 0 a 127.
unsigned char
, para poder representar valores de o a 255.
Caracteres multibyte
O maior problema das codificações ISO-8859 é o uso de somente um byte por caractere, o que limita cada code page a 256 caracteres. Essa limitação impede a representação completa de línguas asiáticas e do árabe, por exemplo.
Para representar conjuntos com mais de 256 caracteres é necessário usar caracteres multibyte, ou seja, com mais de um byte. Por exemplo, se usarmos 2 bytes por caractere é possível representar até 216 = 65.536 caracteres distintos na mesma tabela, sem precisar trocar de code page.
Vários padrões de codificação multibyte foram propostos, como:
- ISO-2022-CJK: chinês, japonês, coreano
- Shift-JIS: japonês (Windows)
- GB 18030: padrão oficial chinês
- Big5: chinês tradicional (Taiwan)
- Unicode
Alguns destes padrões definem todos os caracteres com uma quantidade fixa de bits (16 ou 32), enquanto outros definem caracteres com tamanho variável (8, 16 ou 32 bits).
Unicode
O padrão Unicode define um imenso conjunto de caracteres e os modos de codificação dos mesmos. Atualmente, existem cerca de 140.000 caracteres definidos em Unicode, para todas as línguas conhecidas (inclusive Klingon!), além de símbolos e emojis. Eles ocupam pouco mais de 10% da capacidade total desse padrão.
Em Unicode, cada caractere possui um código numérico único, chamado code point, que pode ser representado de diversas formas. Por exemplo, o code point do emoji 😜 vale 128540 (1F61Ch) e pode ser representado como:
U+1f61c
: em hexadecimal😜
ou😜
: em páginas Web (decimal ou hexadecimal)\u1f61c
: em algumas linguagens de programação
Caracteres em Unicode podem ser codificados (representados em bytes) de diversas formas:
- UTF-8: 8-bit Unicode Transformation Format, usa de 1 a 4 bytes por caractere. É usado no Linux, Windows 10 e outros sistemas recentes.
- UTF-16: usa 2 ou 4 bytes por caractere; muito usado nas APIs dos sistemas Windows, em Java, Python e PHP.
- UTF-32: usa sempre 4 bytes por caractere. É pouco usado na prática.
A codificação UTF-8
UTF-8 é certamente a codificação multibyte mais utilizada hoje em dia, por ser plenamente compatível com a codificação ASCII e por ser econômica em espaço.
Em UTF-8, cada caractere Unicode é codificado usando de 1 a 4 bytes, conforme o número de bits de seu code point:
Caractere | Code point | Em binário | bits |
---|---|---|---|
A | 41h (65) | 100 0001 | 7 |
ç | E7h | 1110 0111 | 8 |
© | C2A9h | 1100 0010 1010 1001 | 16 |
😀 | 1F600h | 1 1111 0110 0000 0000 | 17 |
A regra de codificação de cada caractere é escolhida conforme o número de bits usados pelo seu code point:
# de bits do caractere | formato codificado | bytes | Uso |
---|---|---|---|
até 7 bits | 0xxx-xxxx | 1 | tabela ASCII |
8-11 bits | 110x-xxxx 10xx-xxxx | 2 | caracteres estendidos |
12-16 bits | 1110-xxxx 10xx-xxxx 10xx-xxxx | 3 | caracteres estendidos |
17-21 bits | 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx | 4 | caracteres estendidos |
Pode-se observar que bytes os bytes iniciando em 0…
sempre representam caracteres ASCII. Então, um texto codificado em UTF-8 contendo somente caracteres com códigos entre 0 e 127 equivale a um texto codificado em ASCII padrão.
Além disso, todos os bytes iniciando em 10…
são bytes de continuação da codificação de um caractere multibyte. Isso significa que é fácil localizar o início de cada caractere no texto, mesmo na presença de erros.
xxd
.
O mecanismo de codificação de code points Unicode em UTF-8 funciona da seguinte forma:
- Dado um caractere, verifica-se quantos bits são necessários para armazenar seu código em UTF-8. Por exemplo, o caractere 😀 (code point
U+1f600
) precisa de 17 bits: 1F600 → 1 1111 0110 0000 0000. - Para 17 bits é necessário codificar usando 4 bytes (faixa 17-21 bits)
- Distribui-se os bits do código numérico do caractere nos espaços disponíveis:
Code point (hex) 1 f 6 0 0 Code point (bin) 0001 1111 0110 0000 0000 Encoding format 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx Code point (bin) 000 01 1111 01 1000 00 0000 Encoded character 1111 0000 1001 1111 1001 1000 1000 0000 f 0 9 f 9 8 8 0
- Com isso, a codificação de U+1f600 em UTF-8 resulta nos 4 bytes
f0 9f 98 80
. - A decodificação (de UTF-8 para o code point) se efetua fazendo o caminho inverso.
Alguns arquivos codificados em UTF-* podem apresentar em seus dois primeiros bytes um valor chamado BOM (Byte Order Mark), que define em que ordem os bytes de cada caractere devem ser considerados: big endian ou little endian. o campo BOM não é necessário em UTF-8, mas pode estar presente às vezes:
Bytes | Encoding Form |
---|---|
00 00 FE FF | UTF-32, big-endian |
FF FE 00 00 | UTF-32, little-endian |
FE FF | UTF-16, big-endian |
FF FE | UTF-16, little-endian |
EF BB BF | UTF-8 |
ctrl
+ shift
+ u
, código hexadecimal, enter
Comparando as codificações
O quadro a seguir compara a representação da string “equação” usando algumas das codificações estudadas. No caso da codificação ASCII, considera-se a letra sem acento ou cedilha; a representação UTF-16 usa dois bytes de cabeçalho BOM (Byte Order Mark).
Codificação | BOM | e | q | u | a | ç | ã | o | |
---|---|---|---|---|---|---|---|---|---|
ASCII | 65 | 71 | 75 | 61 | 63 | 61 | 6f | 00 |
|
ISO-8859-1 | 65 | 71 | 75 | 61 | e7 | e3 | 6f | 00 |
|
UTF-8 | 65 | 71 | 75 | 61 | c3 a7 | c3 a3 | 6f | 00 |
|
UTF-16 (be) | fe ff | 00 65 | 00 71 | 00 75 | 00 61 | 00 e7 | 00 e3 | 00 6f | 00 00 |
Conversão de codificações
O comando file
do UNIX informa o tipo de codificação usado em um arquivo de texto:
$ file exemplo.* exemplo.c: C source, ISO-8859 text exemplo.html: HTML document, ASCII text exemplo.txt: UTF-8 Unicode text
A conversão de codificação de um arquivo de texto pode ser feita com utilitários específicos, como o iconv
no Linux:
iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt
Além disso, os editores de texto geralmente permitem escolher a codificação ao salvar o arquivo. Por exemplo, no VI:
:set fileencoding=utf8 :w myfilename
Mais informações
Sobre codificações e Unicode: