Unicode e UTF-8

  ! ? @ + - * / = < >
  0 1 2 3 4 5 6 7 8 9
  A E I O U C …
  Á Â Ã É Í Ó Ô Õ Ú Ç …
  ≡ ≠ ≤ ≥
  Γ Δ Π Σ Ω
  ⋮
  

Esta página faz uma rápida introdução aos conceitos de Unicode, esquema de codificação, e UTF-8.  Para mais informações sobre o assunto veja os artigos indicados no fim da página.

Sumário:

Caracteres

Um caractere é um símbolo tipográfico usado para escrever texto em alguma língua.  (Embora imperfeita, essa definição é suficiente para nossas necessidades.)  É importante não confundir o conceito de caractere com o tipo-de-dados char da linguagem C. Eis alguns exemplos de caracteres:

! " - 9 A B a b ~ À ã ç é ÿ Σ α — “

O número de caracteres usados pelas diferentes línguas do mundo é muito grande.  O português usa apenas 127 caracteres e o inglês fica satisfeito com 94 desses. Mas não podemos nos limitar a essas duas línguas porque estamos expostos a muitas outras línguas, às vezes várias numa mesma sentença. A isso se somam os caracteres especiais usados por várias áreas da ciência.

Para começar a organizar essa Torre de Babel, é preciso dar nomes a todos os caracteres.  O consórcio Unicode de empresas de informática atribuiu nomes numéricos (conhecidos como code points) a mais de 1 milhão de caracteres.  Segue uma minúscula amostra da lista de caracteres e seus números:

número Unicode    caractere
33 !
34 "
45 -
57 9
65 A
66 B
97 a
98 b
126 ~
192 À
227 ã
231 ç
233 é
255 ÿ
931 Σ
945 α
8212
8220

Nessa amostra, os nomes numéricos dos caracteres estão escritos em notação decimal. Em geral, entretanto, esses nomes são escritos em notação hexadecimal. Além disso, é usual acrescentar o prefixo U+ a cada número:

Unicode caractere
U+0021 !
U+0022 "
U+002D -
U+0039 9
U+0041 A
U+0042 B
U+0061 a
U+0062 b
U+007E ~
U+00C0 À
U+00E3 ã
U+00E7 ç
U+00E9 é
U+00FF ÿ
U+03A3 Σ
U+03B1 α
U+2014
U+201C

A lista completa de caracteres e seus números Unicode pode ser vista na página List of Unicode characters da Wikipedia ou na página Unicode / Character reference do Wikibooks.

O conjunto de todos os caracteres da lista Unicode pode ser chamado alfabeto Unicode e cada caractere desse alfabeto pode ser chamado caractere Unicode.  (Se a pretensão do projeto Unicode for justificada, todos os caracteres de todas as línguas do mundo são caracteres Unicode.)

Caracteres ASCII

Os primeiros 128 caracteres da lista Unicode são os mais usados.  Esse conjunto de caracteres vai de U+0000 a U+007F e é conhecido como alfabeto ASCII.  Os elementos desse alfabeto serão chamados caracteres ASCII.  O alfabeto ASCII contém letras, dígitos decimais, sinais de pontuação, e alguns caracteres especiais. A lista dos 128 caracteres ASCII e seus números Unicode está registrada na Tabela ASCII.

Infelizmente o alfabeto ASCII não é suficiente para escrever texto em português, pois não contém letras com sinais diacríticos.

Esquemas de codificação

Como armazenar os caracteres Unicode em arquivos digitais e na memória? Poderíamos representar cada caractere pelo seu número Unicode escrito em notação binária. Mas isso exigiria 3 bytes por caractere, o que é muito ineficiente dado que apenas 1 byte é suficiente para os caracteres mais comuns. É preciso recorrer, então, a representações mais complexas.

Um esquema de codificação (= character encoding) é uma tabela que associa uma sequência de bytes com cada número Unicode, e portanto com cada caractere Unicode.  (Em geral, omitimos a palavra esquema e dizemos apenas codificação.)  A sequência de bytes associada com um caractere é o código do caractere.  As próximas seções examinam dois esquemas de codificação: ASCII e UTF-8.

Código ASCII

O código ASCII é muito simples: o número Unicode de cada caractere é escrito em notação binária.  Esse código é usado apenas para o alfabeto ASCII.  Como o alfabeto tem apenas 128 caracteres, o código ASCII necessita de apenas 1 byte por caractere e o primeiro bit desse byte é 0.  Segue uma amostra da tabela de códigos:

Unicode       ASCII  hexa  
U+0021 ! 00100001 0x21
U+0022 " 00100010 0x22
U+002D - 00101101 0x2D
U+0039 9 00100111 0x39
U+0041 A 01000001 0x41
U+0042 B 01000010 0x42
U+0061 a 01100001 0x61
U+0062 b 01100010 0x62
U+007E ~ 01111110 0x7E

A última coluna traz o código ASCII escrito em notação hexadecimal.

(Por que não aproveitar todos os 8 bits de um byte?  Com isso, poderíamos codificar 128 caracteres adicionais além dos 128 do alfabeto ASCII.  O código ISO-LATIN-1 faz exatamente isso, mas caiu em desuso.  O conjunto ISO-LATIN-1 de caracteres inclui, entre outros, os caracteres  ª ± º ¼ ½ ¾ À Á Â Ã Ç È É Ê Ì Í Î Ò Ó Ô × Ù Ú Û à á â ã ç è é ê ì í î ò ó ô õ ÷ ù ú û . Os nomes numéricos desses caracteres são iguais na tabela ISO-LATIN-1 e na tabela Unicode.)

Código UTF-8

Se usássemos um número fixo de bytes por caractere, precisaríamos de 3 bytes. A solução é recorrer a um código multibyte, que emprega um número variável de bytes por caractere: alguns caracteres usam 1 byte, outros usam 2 bytes, e assim por diante.

O código multibyte mais usado é conhecido como UTF-8.  Ele associa uma sequência de 1 a 4 bytes (8 a 32 bits) com cada caractere Unicode.  Os primeiros 128 caracteres usam o velho e bom código ASCII de 1 byte por caractere.  Os demais caracteres têm um código mais longo.  Veja uma minúscula amostra:

Unicode       código UTF-8 hexa
U+0021 ! 00100001 0x21
U+0022 " 00100010 0x22
U+002D - 00101101 0x2D
U+0039 9 00100111 0x39
U+0041 A 01000001 0x41
U+0042 B 01000010 0x42
U+0061 a 01100001 0x61
U+0062 b 01100010 0x62
U+007E ~ 01111110 0x7E
U+00C0 À 11000011 01000000 0xC380
U+00E3 ã 11000011 10100011 0xC3A3
U+00E7 ç 11000011 10100111 0xC3A7
U+00E9 é 11000011 10101001 0xC3A9
U+00FF ÿ 11000011 10111111 0xC3BF
U+03A3 Σ 11001110 10100011 0xCEA3
U+03B1 α 11001110 10110001 0xCEB1
U+2014 11100010 10000000 10010100 0xE28094
U+201C 11100010 10000000 10011100  0xE2809C

(A última coluna traz o código UTF-8 escrito em notação hexadecimal.)  A lista dos códigos UTF-8 de todos os caracteres Unicode pode ser vista em UTF-8 encoding table and Unicode characters ou na página Unicode / Character reference do Wikibooks.  Por exemplo, a cadeia de caracteres  ação  é representada em UTF-8 pela seguinte sequência de bytes:

0x61 0xC3 0xA7 0xC3 0xA3 0x6F
a ç ã o

Todas as letras com sinais diacríticos usadas em português são representados em UTF-8 por apenas 2 bytes, o primeiro dos quais é 0xC3 (195 em notação decimal).

Decodificação.  Como o número de bytes por caractere não é fixo, a decodificação de uma sequência de bytes não é fácil. Como saber onde termina o código de um caractere e começa o código do caractere seguinte?  O esquema de codificação UTF-8 foi construído de modo que os primeiros bits do código de um caractere dizem quantos bytes o código ocupa.  Assim, se o primeiro bit é 0, e portanto o valor do primeiro byte é menor que 128, então esse é o único byte do caractere.  Se o valor do primeiro byte pertence ao intervalo 192 .. 223 então o código do caractere tem dois bytesE assim por diante.

Suporemos UTF-8.  A linguagem de programação C não prescreve um esquema de codificação específico. Mas o código mais usado é UTF-8, tanto para entrada e saída quanto para a representação interna de caracteres.  O presente sítio supõe que todos os arquivos de texto, sejam eles programas ou dados, usam código UTF-8. (Mas em muitos exemplos apenas o subconjunto ASCII de UTF-8 é usado.)

Exercícios 1

  1. A seguinte sequência de bytes está em notação decimal. Que cadeia de caracteres esses bytes representam em código UTF-8?
    67 195 179 100 105 103 111
    
  2. A seguinte sequência de bytes está em notação hexadecimal. Que cadeia de caracteres esses bytes representam em código UTF-8?
    0x41 0x74 0x65 0x6E 0xC3 0xA7 0xC3 0xA3 0x6F 0x21
    
  3. Consulte a tabela UTF-8 encoding table and Unicode characters (ou outra semelhante) para verificar que todas as letras com sinais diacríticos usadas em português são representados em UTF-8 por apenas 2 bytes, o primeiro dos quais é 0xC3 (195 em notação decimal).
  4. Escreva uma função que receba um arquivo que contém texto em código UTF-8 e decida se cada byte do arquivo representa um único caractere (ou seja, se o alfabeto do arquivo é ASCII).
  5. Escreva as sequências de bytes que representam, em código UTF-8, cada uma das seguintes cadeias de caracteres:
    • ASCII string
    • Atenção!
    • π = 3.14±0.01
    • ⌊9.9⌋ = 9
    • v[n] = ∞

    (Consulte a página UTF-8 encoding table and Unicode characters. Use o botão go to other block para ver as várias partes da tabela.)

Qual o código usado pelo meu arquivo?

Não há como saber, com certeza, qual o esquema de codificação usado por um dado arquivo de texto. O autor do arquivo precisa informar, fora do arquivo, qual código usou.

Há utilitários (como file, por exemplo) que examinam um arquivo e tentam adivinhar, com algum grau de confiança, o seu esquema de codificação.

Se souber qual o esquema de codificação usado por seu arquivo, você pode usar o aplicativo iconv para mudar a codificação (convertendo, por exemplo, um arquivo codificado em ISO-LATIN-1 em um arquivo equivalente codificado em UTF-8).

Exercícios 2

  1. Os programas od e hexdump imprimem a sequência de bytes de um arquivo sem convertê-los em caracteres. Use um desses utilitários para examinar o conteúdo de um arquivo e procure adivinhar o esquema de codificação usado.
  2. A função isalpha da biblioteca ctype só reconhece letras do alfabeto ASCII (sem sinais diacríticos, portanto).  Escreva uma extensão de isalpha que reconheça letras com diacríticos.  Sua função deve receber uma string que contém a codificação UTF-8 de um caractere e decidir se o código representa uma letra (com sinal diacrítico ou não).