Padrão Unicode
Para um computador, tudo é número. Uma foto é uma grade de números que dizem a cor de cada ponto, e uma música é uma longa sequência de números que descrevem a pressão do ar a cada instante. Com o texto não é diferente: cada letra, cada acento, cada ideograma chinês e cada emoji que aparece na sua tela está guardado na memória como um número. Digite qualquer coisa no campo abaixo e acompanhe o caminho do texto até os bytes:
Na primeira etapa estão os caracteres, do jeito que você os vê. Na segunda, cada um recebe o seu número, chamado de ponto de código e escrito em hexadecimal depois de “U+”. Na terceira, esses números são transformados em bytes, para serem gravados num arquivo ou enviados pela rede. Repare que os caracteres não ocupam todos o mesmo espaço: as letras sem acento usam um byte, as acentuadas usam dois, os ideogramas chineses, três, e o emoji, quatro.
Quem define o número de cada caractere é o Unicode, um padrão mantido por um consórcio de empresas, governos, universidades e especialistas. A versão 18.0, publicada em setembro de 2026, tem 172 808 caracteres de 175 sistemas de escrita, das letras do alfabeto latino aos hieróglifos egípcios, passando por símbolos matemáticos, notas musicais e milhares de emojis. Praticamente todo o texto que circula hoje em computadores e celulares é Unicode.
Mas nem sempre foi assim. Neste guia, vamos ver como funcionavam as primeiras tabelas de caracteres e por que elas se multiplicaram até virar um problema, como o Unicode organiza o seu enorme espaço de números e como esses números viram bytes. Depois, veremos que “caractere” é uma ideia mais escorregadia do que parece: há acentos que se combinam com letras, emojis feitos de vários pedaços, escritas que correm da direita para a esquerda e letras que se passam por outras.
Letras como números
A ideia de representar letras por números é mais antiga que o computador. No telégrafo que o francês Émile Baudot criou nos anos 1870, cada letra era transmitida como uma combinação de cinco sinais elétricos, cada um ligado ou desligado. Cinco sinais desse tipo, que hoje chamaríamos de bits, formam 25 = 32 combinações, pouco para 26 letras, dez algarismos e a pontuação. O código contornava o problema com dois sinais especiais, que alternavam entre o modo de letras e o de algarismos, como a tecla de maiúsculas de um teclado.
Com os computadores, surgiram dezenas de códigos diferentes, quase um para cada fabricante, até que, em 1963, a associação americana de normas técnicas publicou o ASCII, sigla de American Standard Code for Information Interchange. O ASCII usa 7 bits, o que dá 128 códigos, numerados de 0 a 127. Desde a revisão de 1967, que acrescentou as letras minúsculas, a tabela praticamente não mudou. Passe o mouse ou toque nas peças para ver o número de cada uma:
Os números aparecem em hexadecimal, a base 16, em que os dígitos vão de 0 a 9 e continuam de A a F. Cada dígito hexadecimal corresponde a exatamente 4 bits, e por isso essa notação é tão comum entre quem lida com bytes. Na tabela, a coluna dá o último dígito e a linha, o primeiro: o “A”, na linha 4 e na coluna 1, tem o código 41 em hexadecimal, que é 4 × 16 + 1 = 65 em decimal.
Os 32 primeiros códigos, e também o último, não são letras, mas caracteres de controle, comandos para os teletipos e terminais da época. O 7, BEL, fazia tocar a campainha do teletipo. O 13, CR, de carriage return, levava o carro de impressão de volta ao começo da linha, e o 10, LF, de line feed, fazia o papel avançar uma linha. Até hoje, o Windows termina cada linha de um arquivo de texto com o par CR LF, enquanto o Linux e o macOS usam só o LF, e essa diferença ainda causa pequenas confusões quando arquivos passam de um sistema para outro.
A tabela foi planejada com cuidado. Os algarismos começam no código 48, de modo que os quatro bits da direita de cada um formam o seu próprio valor: o “7” é 011 0111, e 0111 é 7 em binário. As maiúsculas começam no 65, e as minúsculas, no 97, exatamente 32 posições depois. Como 32 é uma potência de 2, cada letra difere da sua versão minúscula num único bit, e trocar maiúsculas por minúsculas é só uma questão de ligar ou desligar esse bit. Já o último código, 127, DEL, tem os sete bits ligados, e não por acaso: numa fita de papel perfurado, em que cada furo era um bit 1, qualquer caractere podia ser apagado furando todas as posições.
Para o inglês, 128 códigos bastavam. Mas o ASCII não tem “ç”, nem “ã”, nem “é”. Para escrever em português, e em quase qualquer outra língua, era preciso ir além.
Um byte, muitas tabelas
Quando os computadores passaram a guardar cada caractere num byte, de 8 bits, sobrou um bit, e com ele a tabela podia dobrar de tamanho. Os códigos de 0 a 127 continuavam sendo os do ASCII, e os 128 novos, de 128 a 255, ficavam livres para o que faltava. O problema é que cada um preencheu essa metade de um jeito.
O IBM PC, lançado em 1981, usou a metade de cima para algumas letras acentuadas, letras gregas e traços para desenhar molduras na tela. A ISO definiu uma família de tabelas, a ISO 8859, com uma variante para cada região: a 8859-1, também chamada de Latin-1, para as línguas da Europa Ocidental, incluindo o português; a 8859-5 para o cirílico; a 8859-7 para o grego; e assim por diante. A Microsoft criou as suas próprias variantes para o Windows, como a Windows-1252, quase igual à Latin-1, e a Windows-1251, para o cirílico. A Apple tinha outras, e na União Soviética se usava a família KOI8 desde os anos 1970. Cada uma dessas tabelas é uma codificação diferente, ou, no jargão da IBM e da Microsoft, uma página de código.
Um arquivo de texto, porém, é só uma sequência de bytes, e não diz em que tabela foi gravado. Quem o abre precisa adivinhar e, quando erra, os bytes certos viram os caracteres errados. Experimente: escolha como o texto é gravado e depois como ele é lido.
O resultado tem até nome: mojibake, do japonês 文字化け, algo como “caracteres transformados”. Se você já viu “Ação” no lugar de “Ação”, viu um texto gravado em UTF-8, uma codificação que veremos adiante, e lido como Windows-1252. No caminho inverso, um byte que não forma uma sequência válida de UTF-8 é trocado pelo caractere de substituição, U+FFFD, o losango com uma interrogação. Os japoneses deram nome ao fenômeno porque sofriam com ele mais do que ninguém. O japonês tem milhares de caracteres, que não cabem em 256 posições, e os computadores japoneses usavam codificações com vários bytes por caractere, como a Shift JIS e a EUC-JP, incompatíveis entre si. O chinês tinha as suas, a GB 2312 na China continental e a Big5 em Taiwan e Hong Kong, e o coreano, outras ainda.
Algumas tabelas tinham truques engenhosos para sobreviver ao caos. Na KOI8-R, as letras russas ficam nas posições das letras latinas de som parecido, mais 128. Se um servidor de e‑mail antigo apagasse o oitavo bit de cada byte, como muitos faziam, “Привет, мир” (“olá, mundo”) virava “pRIWET, MIR”, com as maiúsculas e minúsculas trocadas, mas ainda legível para um russo. Era uma gambiarra para um problema que só teria solução com uma tabela única para todas as escritas do mundo.
Um número para cada caractere
Em 1987, Joe Becker, da Xerox, e Lee Collins e Mark Davis, da Apple, começaram a estudar como seria um conjunto de caracteres universal. No ano seguinte, Becker publicou um rascunho chamado Unicode 88, que explicava o nome: o novo código deveria ser “único, unificado e universal”. A proposta era dar a cada caractere de cada escrita do mundo um número próprio, que não dependesse de tabela, de fabricante nem de país.
No início de 1991, empresas como Apple, IBM, Microsoft, NeXT e Sun formalizaram o Consórcio Unicode, que publicou a primeira versão do padrão em outubro daquele ano. Ao mesmo tempo, a ISO trabalhava num projeto parecido, a norma ISO/IEC 10646. Em vez de competir, as duas iniciativas se fundiram, e desde 1993 o Unicode e a ISO/IEC 10646 atribuem exatamente os mesmos números aos mesmos caracteres.
O número de um caractere, o seu ponto de código, é escrito em hexadecimal, com pelo menos quatro dígitos, depois do prefixo “U+”: o “A” é U+0041, o “ç” é U+00E7, o “€” é U+20AC e o “😀” é U+1F600. Os 128 primeiros pontos de código são os do ASCII, na mesma ordem, e os 256 primeiros, os da Latin-1. Assim, textos em ASCII ou em Latin-1 puderam ser convertidos para o Unicode sem que nenhum número mudasse.
Além do número, cada caractere recebe um nome oficial, em inglês e em maiúsculas: o “ç” é LATIN SMALL LETTER C WITH CEDILLA. Desde 1996, os nomes nunca mudam depois de publicados, nem quando estão errados. O U+FE18 se chama PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET, com “bracket” escrito errado, e assim ficará para sempre; o consórcio só pôde acrescentar um apelido corrigido. Essa estabilidade é uma regra de ouro do Unicode: programas escritos hoje precisam continuar funcionando com os textos de amanhã, e vice-versa. Digite ou cole qualquer texto para ver o número e o nome de cada caractere:
Alguns nomes nem precisam ser guardados. Os dos ideogramas chineses são formados pelo próprio número, como CJK UNIFIED IDEOGRAPH-4E16 para o 世, e os das sílabas do coreano são montados a partir das letras que as compõem: o 한 é HANGUL SYLLABLE HAN. Para ficar leve, esta página traz os nomes de uma seleção de blocos; os demais estão nas tabelas oficiais do consórcio.
Caracteres e glifos
O Unicode codifica caracteres, não desenhos. Um caractere é uma unidade abstrata da escrita, como “a letra g minúscula”. A forma que ele assume na tela, o glifo, fica por conta da fonte. O mesmo U+0067 pode ter uma perna aberta ou fechada, com ou sem serifas, e continua sendo o mesmo caractere:
Em algumas escritas, a forma depende do contexto. No árabe, que é cursivo, a maioria das letras tem quatro formas, conforme apareça isolada ou no começo, no meio ou no fim de uma palavra, mas cada letra continua sendo um único caractere. Quem escolhe a forma certa é o programa que desenha o texto, seguindo as regras da fonte; no segundo cartão, um caractere invisível de junção, que veremos adiante, força cada uma das formas.
O caso mais delicado é o dos ideogramas chineses, usados também no japonês, no coreano e, no passado, no vietnamita. Muitos deles têm variantes regionais, com pequenas diferenças de traço. Para não codificar o mesmo ideograma várias vezes, o Unicode adotou a unificação han: variantes consideradas o mesmo caractere recebem um único ponto de código, e a diferença fica por conta da fonte. É por isso que, no terceiro cartão, o 骨 e o 直 aparecem de um jeito numa fonte chinesa e de outro numa japonesa. A decisão foi, e ainda é, controversa, sobretudo no Japão, porque obriga o programa a saber em que língua está o texto para escolher a fonte certa.
A separação entre caractere e glifo explica também um fenômeno conhecido. Quando a fonte em uso não tem um desenho para certo caractere, o sistema procura outra que tenha; se nenhuma tiver, aparece um retângulo vazio, apelidado de tofu pela semelhança com o queijo de soja. O texto não está corrompido: o caractere está lá, só não há como desenhá-lo. Foi para acabar com o tofu que o Google criou a família de fontes Noto, cujo nome vem de no more tofu, “chega de tofu”, e que hoje cobre a maior parte das escritas do Unicode.
O espaço de códigos
Os criadores do Unicode imaginaram, de início, que 16 bits seriam suficientes: 65 536 posições pareciam dar para todas as escritas em uso. Não davam. Só os ideogramas chineses, contando as variantes raras e históricas, passam de 100 mil. Na versão 2.0, de 1996, o espaço foi ampliado para 1 114 112 pontos de código, de U+0000 a U+10FFFF, divididos em 17 planos de 65 536 posições cada.
Abaixo, cada plano é uma placa, e cada torre, um grupo de 256 pontos de código consecutivos. A altura da torre mostra quantos deles já têm um caractere atribuído, e a cor indica a região de origem da escrita. Arraste o controle para ver o espaço se encher, versão a versão, e passe o mouse ou toque nas torres para ver o que cada uma contém:
O plano 0, o Plano Multilíngue Básico, ou BMP, concentra os caracteres de uso diário: os alfabetos latino, grego, cirílico, árabe e hebraico, as escritas da Índia e do Sudeste Asiático, o hangul coreano, os silabários japoneses e os ideogramas chineses mais comuns. Ele está quase todo ocupado, e boa parte do que não é escrita está reservada para dois usos especiais. A área de uso privado fica livre para que cada empresa ou programa a use como quiser: é ali que algumas fontes guardam ícones, por exemplo. E os substitutos servem a um truque do UTF-16, que veremos na próxima seção.
O plano 1, o Plano Multilíngue Suplementar, reúne escritas históricas, como os hieróglifos egípcios e o cuneiforme, notação musical, letras matemáticas e a maior parte dos emojis. Os planos 2 e 3 são quase inteiramente de ideogramas; só os ideogramas chineses unificados já somam 101 985. Os planos 4 a 13 estão vazios. O 14 guarda alguns caracteres invisíveis de uso especial, e os planos 15 e 16 são inteiros de uso privado.
Nos últimos anos, uma versão nova do Unicode tem saído todo mês de setembro. A maior de todas foi a 3.1, de 2001, que acrescentou 44 946 caracteres e foi a primeira a ir além do BMP. A mais recente, a 18.0, trouxe 13 007, a maior leva desde então. Dos caracteres novos, 11 328 são da escrita de selo, uma forma dos caracteres chineses que remonta à dinastia Qin, por volta de 200 a.C., e que ainda hoje aparece em carimbos e sinetes. A versão também trouxe o jurchen, a escrita usada no nordeste da China durante a dinastia Jin, três símbolos de moedas e nove emojis. Mesmo assim, depois de 35 anos, os caracteres ocupam cerca de 15% do espaço: há mais de 800 mil posições livres, o que deve bastar por muito tempo.
De números a bytes
Um ponto de código é um número abstrato. Para gravá-lo num arquivo ou enviá-lo pela rede, é preciso decidir como transformá-lo em bytes, e essa regra se chama forma de codificação. O Unicode define três: UTF-32, UTF-16 e UTF-8. A sigla UTF vem de Unicode Transformation Format, e o número indica o tamanho, em bits, da unidade básica de cada uma.
O UTF-32 é o mais simples: cada ponto de código ocupa 32 bits, ou 4 bytes, sempre. Como o maior ponto de código, U+10FFFF, tem 21 bits, os outros 11 ficam em zero. O UTF-32 é cômodo para os programas, porque todos os caracteres têm o mesmo tamanho e é fácil saltar para qualquer um deles no meio do texto. Mas desperdiça muito espaço: num texto em português, três de cada quatro bytes são zeros.
O UTF-16 usa unidades de 16 bits. Os pontos de código do BMP, que cabem em 16 bits, ocupam uma unidade, com o próprio número. Os dos outros planos não cabem, e aí entram os substitutos (surrogates, em inglês): as 2 048 posições de U+D800 a U+DFFF, que o Unicode reservou e nunca atribuirá a caractere algum. Do ponto de código se subtrai 10000 em hexadecimal, e o resultado, que cabe em 20 bits, é dividido em duas metades de 10 bits. A primeira metade é somada a D800, e a segunda, a DC00, formando um par de substitutos. Nos bits, isso equivale a pôr os prefixos 110110 e 110111 na frente de cada metade:
O “😀”, U+1F600, fica fora do BMP. Tirando 10000, sobra F600, e o par resultante é D83D DE00. Como as unidades desse intervalo não significam nada sozinhas, um programa que lê UTF-16 reconhece o par sem ambiguidade. Os outros exemplos, como o “€”, ocupam uma unidade só; e, em UTF-32, qualquer um deles ocupa uma unidade de 32 bits com os bits de cima zerados.
O Windows, o Java e o JavaScript adotaram o Unicode cedo, com unidades
de 16 bits, na época em que se acreditava que isso bastaria, e por isso
até hoje tratam o texto como uma sequência de unidades de UTF-16. Num
navegador, "😀".length vale 2, porque o JavaScript conta unidades de
UTF-16, não caracteres.
UTF-8
Numa noite de setembro de 1992, num restaurante de Nova Jersey, Ken Thompson rabiscou num jogo americano, diante do colega Rob Pike, uma terceira forma de codificação. Os dois trabalhavam nos Laboratórios Bell, no sistema operacional Plan 9, e em menos de uma semana o sistema já rodava inteiramente com ela. Hoje é, de longe, a mais usada de todas: o UTF-8.
No UTF-8, cada ponto de código ocupa de 1 a 4 bytes, conforme o tamanho do número. Até U+007F basta um byte, idêntico ao do ASCII. Até U+07FF, faixa que inclui as letras acentuadas e os alfabetos grego, cirílico, hebraico e árabe, são dois bytes; até U+FFFF, o resto do BMP, três; e daí em diante, quatro. Os primeiros bits de cada byte dizem qual é o seu papel. Um byte que começa com 0 é um caractere ASCII completo; os que começam com 110, 1110 ou 11110 abrem uma sequência de 2, 3 ou 4 bytes; e os que começam com 10 são continuações. Os bits do ponto de código preenchem as posições que sobram:
O “ç”, U+00E7, é 1110 0111 em binário e não cabe nos 7 bits livres de um byte só. Vai então para o modelo de dois bytes, 110xxxxx 10xxxxxx, que tem 11 posições livres. Completados com zeros à esquerda, os bits formam os bytes C3 A7, os mesmos que, lidos como Windows-1252, apareceram como “ç” no painel das tabelas. Esse desenho tem várias qualidades:
- Todo texto em ASCII já é UTF-8 válido, byte por byte, e os programas antigos continuaram funcionando.
- Os bytes das sequências longas são todos maiores que 127 e nunca se confundem com um caractere ASCII. Uma barra ou um byte zero dentro de um nome de arquivo continuam significando o que sempre significaram, e isso permitiu adotar o UTF-8 sem reescrever os sistemas operacionais.
- É fácil se localizar: basta olhar os primeiros bits de um byte para saber se ele começa ou continua um caractere. Se um byte se perder, ou se a leitura começar no meio do texto, só um caractere se estraga, e o resto é lido normalmente.
- Não há dúvida sobre a ordem dos bytes. No UTF-16 e no UTF-32, cada unidade tem vários bytes, e alguns computadores gravam primeiro o byte mais significativo, enquanto outros gravam primeiro o menos significativo. O UTF-8 é lido byte a byte.
- Ordenar textos em UTF-8 byte a byte dá a mesma ordem que ordenar os pontos de código.
O preço é que o tamanho do texto varia de escrita para escrita. Abaixo, a frase de abertura da Declaração Universal dos Direitos Humanos em várias línguas, com o número médio de bytes por ponto de código em cada codificação. Passe o mouse ou toque nas barras para ver a frase e os totais, e experimente com um texto seu:
Em inglês, e em português sem acentos, como nessa frase, o UTF-8 gasta exatamente um byte por caractere; cada letra acentuada acrescenta só mais um. Em russo, grego e árabe, fica perto de dois, porque as letras ocupam dois bytes, mas os espaços e a pontuação continuam ocupando um. O hindi, o chinês e o japonês são os casos em que o UTF-16 leva vantagem: os seus caracteres ocupam três bytes em UTF-8 e só dois em UTF-16. Na prática, porém, o texto raramente anda sozinho. Uma página web em chinês vem cheia de marcação HTML, que é ASCII, e em UTF-8 acaba ficando menor.
Por tudo isso, o UTF-8 venceu. Segundo a W3Techs, ele é usado por 99,1% dos sites cuja codificação é conhecida. É a codificação exigida pelo padrão atual do HTML e pelo JSON trocado entre sistemas, e a padrão no Linux, no macOS e na maioria das linguagens de programação modernas. O UTF-16 continua vivo dentro dos programas, mas raramente é usado para gravar arquivos ou trocar dados.
Resta uma curiosidade: o caractere U+FEFF, a marca de ordem de bytes, ou BOM, de byte order mark. No UTF-16, ele vai no início do arquivo para indicar em que ordem vêm os bytes de cada unidade. O UTF-8 não precisa dele, mas alguns programas o gravavam mesmo assim, como uma assinatura; foi o caso do Bloco de Notas do Windows durante muitos anos. Em UTF-8, o BOM vira os bytes EF BB BF, e quem já abriu um arquivo que começava com “” viu esses três bytes lidos como Windows-1252.
Acentos que se combinam
Até aqui, tratamos cada caractere como um número. Mas há letras que podem ser escritas de mais de um jeito. O “á” existe no Unicode como um caractere pronto, U+00E1, herdado da Latin-1. E existe também como a soma de duas peças: um “a” comum, U+0061, seguido do U+0301, o acento agudo combinante, um caractere que não aparece sozinho e se desenha sobre o caractere anterior.
Os sinais combinantes permitem escrever qualquer combinação de letra e acento, inclusive as que nenhuma língua usa. Escolha uma letra e acrescente sinais:
Os sinais se acumulam na ordem em que são digitados, e a fonte tenta arrumá-los acima ou abaixo da letra. Há centenas deles, usados por línguas do mundo todo. O vietnamita, por exemplo, põe com frequência dois sinais na mesma vogal, como em “ệ”. E nada impede que se empilhem dezenas de sinais sobre uma mesma letra, uma brincadeira que ficou conhecida na internet como texto zalgo.
Ter duas grafias para o mesmo texto cria um problema. Se você procurar “José” num documento em que o nome foi gravado com o acento separado, uma comparação byte a byte não o encontra: para o computador, são sequências diferentes. A solução do Unicode é a normalização, que reescreve o texto numa forma padrão. Na forma NFC, as letras são compostas sempre que existe um caractere pronto; na NFD, todas são decompostas em letra mais sinais. Duas grafias equivalentes ficam idênticas depois de normalizadas na mesma forma. Os pontos de código que mudam aparecem destacados:
A NFC é a forma mais comum, recomendada para a web e produzida pela maioria dos teclados. Mas não é universal. O sistema de arquivos HFS+, o padrão dos Macs até a chegada do APFS, em 2017, gravava os nomes de arquivos decompostos, e arquivos criados nesses computadores e copiados para outros sistemas podem até hoje carregar os nomes na forma NFD, o que confunde os programas que comparam nomes byte a byte.
Há ainda as formas de compatibilidade, NFKC e NFKD, que vão além e trocam caracteres que existem por razões históricas ou tipográficas pelos seus equivalentes simples. A ligadura “fi” vira “f” e “i”, o “²” vira “2”, e o “A” largo, usado em textos do Leste Asiático, vira um “A” comum. Essas formas perdem informação, mas são úteis em buscas e na comparação de nomes de usuário, que não deveriam ser diferentes só porque um deles usa letras largas.
O que é um caractere?
A esta altura, a palavra “caractere” já está esticada demais. O “á” da seção anterior pode ser um ponto de código ou dois, mas quem lê vê uma letra só. Aquilo que o leitor percebe como uma unidade é o que o Unicode chama de grafema, e há regras oficiais para agrupar os pontos de código em grafemas. Com os emojis, a distância entre as duas coisas fica enorme. Escolha um exemplo e separe as peças:
Os emojis surgiram nos celulares japoneses no fim dos anos 1990, e cada operadora tinha o seu conjunto. Quando empresas como o Google e a Apple precisaram trocar mensagens com esses aparelhos, os emojis foram incorporados ao Unicode, e a maior parte deles entrou na versão 6.0, de 2010. Desde então, novos emojis surgem não só com pontos de código novos, mas também da combinação dos que já existem.
A família é formada por quatro emojis de pessoas, ligados pelo U+200D, a junção de largura zero, ou ZWJ, de zero width joiner. É um caractere invisível que diz à fonte: “se você tiver um desenho para esta combinação, use-o”. Se a fonte não tiver, as quatro pessoas aparecem lado a lado. Os tons de pele, que chegaram em 2015, são modificadores baseados na escala de Fitzpatrick, usada por dermatologistas, e alteram o emoji que vem antes deles. E as bandeiras de países não têm pontos de código próprios: cada uma é um par de indicadores regionais, letras especiais que formam o código de duas letras do país, “BR” no caso do Brasil. Assim, o Unicode não precisa decidir quais países merecem uma bandeira.
Os grafemas também importam longe dos emojis. No coreano, a sílaba 각 pode ser guardada como um único ponto de código ou como três peças, as letras ㄱ, ㅏ e ㄱ, que a fonte monta num bloco. No hindi, a sílaba “नि” é guardada como a consoante “न” seguida da vogal “ि”, mas a vogal é desenhada antes da consoante. A ordem na memória nem sempre é a ordem no papel.
Tudo isso tem consequências práticas. Cada linguagem de programação conta os caracteres de um jeito: para a família, o Python responde que o texto tem 7 caracteres, porque conta pontos de código, e o JavaScript responde 11, porque conta unidades de UTF-16. Em UTF-8, são 25 bytes, e só a contagem de grafemas dá 1. Um programa que corta um texto longo para caber na tela, ou que limita o tamanho de um nome, precisa cortar entre os grafemas, e não no meio deles, ou pode separar um tom de pele do seu emoji ou um acento da sua letra.
Da direita para a esquerda
O árabe e o hebraico são escritos da direita para a esquerda. Os números, porém, continuam sendo escritos da esquerda para a direita, mesmo no meio de um texto árabe, e é comum misturar palavras das duas direções numa mesma frase. Como guardar um texto assim?
O Unicode guarda tudo em ordem lógica, a ordem em que o texto é lido e digitado, e deixa para o programa que o desenha a tarefa de arrumar cada trecho na direção certa, seguindo o algoritmo bidirecional, um conjunto de regras publicado pelo consórcio. Cada caractere tem uma direção: as letras latinas vão para a direita, as árabes e hebraicas vão para a esquerda, os algarismos formam blocos próprios, e os espaços e a pontuação são neutros e assumem a direção dos vizinhos. Na figura, o texto aparece em cima como você o veria na tela, e embaixo estão os pontos de código na ordem em que ficam guardados:
No primeiro exemplo, a palavra árabe, “olá”, está guardada na ordem em que é lida, da primeira letra à última, mas aparece invertida em relação à memória, com a primeira letra à direita. No segundo, a frase inteira é hebraica, e o número 4521, embora cercado de palavras que correm para a esquerda, continua sendo lido da esquerda para a direita.
Para os casos em que as regras automáticas não dão conta, existem
caracteres de controle invisíveis que forçam uma direção. O U+202E,
RIGHT-TO-LEFT OVERRIDE, faz tudo o que vem depois dele ser desenhado da
direita para a esquerda, e já foi muito usado para disfarçar arquivos.
No terceiro exemplo, o nome de um programa, que termina em “.exe”,
aparece na tela como fotogpj.exe, uma
inocente imagem “.jpg”.
Em 2021, dois pesquisadores da Universidade de Cambridge mostraram que o truque também funciona em código-fonte. Com esses caracteres escondidos em comentários e em textos entre aspas, um programa pode ser exibido de um jeito no editor e compilado de outro, o que permitiria esconder uma porta dos fundos num código aparentemente inocente. O ataque foi batizado de Trojan Source, e desde então compiladores, editores e sites como o GitHub passaram a emitir alertas quando encontram esses caracteres.
Letras parecidas
Com mais de 170 mil caracteres, é inevitável que alguns sejam idênticos a outros na tela. O “а” cirílico, U+0430, é indistinguível do “a” latino, U+0061, na maioria das fontes, e o mesmo vale para “е”, “о”, “р” e “с”, entre outros. Caracteres diferentes com a mesma aparência são chamados de homóglifos.
Isso seria só uma curiosidade, não fossem os endereços da internet. Desde 2003, os nomes de domínio podem ter letras de qualquer escrita, o que permite endereços em chinês, em árabe ou com acentos, como “açaí.com.br”. Mas também permite registrar um nome com letras cirílicas que imite o de um banco ou de uma loja, e usá-lo para roubar senhas. Em 2017, um pesquisador registrou “аррӏе.com”, escrito só com letras cirílicas, e mostrou que o Chrome, o Firefox e o Opera o exibiam exatamente como “apple.com”. Veja a que escrita pertence cada letra de um endereço:
Na verdade, o sistema de nomes da internet, o DNS, continua limitado ao ASCII. Antes de consultá-lo, o navegador converte um nome com outros caracteres para uma forma chamada Punycode, que começa com “xn--”: “аррӏе.com” vira “xn--80ak6aa92e.com”. Para proteger os usuários, os navegadores mostram o Punycode no lugar das letras quando um nome mistura escritas ou quando é todo escrito em letras que imitam outra escrita. E o consórcio mantém uma lista oficial de caracteres que podem ser confundidos entre si, usada por navegadores, registros de domínios e redes sociais.
Maiúsculas e ordem alfabética
Operações que parecem triviais, como passar um texto para maiúsculas, dependem da língua. Em alemão, o “ß” vira “SS” em maiúsculas, e a palavra fica mais comprida. Em turco, o “i” com pingo e o “ı” sem pingo são letras diferentes, cada uma com a sua maiúscula, “İ” e “I”; um programa que não sabe que o texto é turco passa o “i” para “I” e troca uma letra pela outra. E em grego, o sigma minúsculo tem uma forma especial no fim das palavras. Veja o que o seu navegador faz com cada caso:
Ordenar palavras é ainda mais difícil. Pelos pontos de código, o “Z” vem antes do “a”, e as letras acentuadas vão para depois do “z”: o “Á”, 193, fica depois do “z”, 122. Nenhum dicionário funciona assim. Compare:
Para ordenar como um dicionário, o Unicode define um algoritmo de ordenação, que compara primeiro as letras, depois os acentos e só então as maiúsculas e minúsculas. As particularidades de cada língua, como o “ch” do espanhol tradicional, que vinha depois de todas as palavras com “c”, ou o “å” do sueco, que vem depois do “z”, ficam num grande banco de dados mantido pelo consórcio, o CLDR, que também registra como cada país escreve datas, números e moedas. Quando o seu celular ordena os contatos ou escreve “28 de setembro de 2026”, é bem provável que esteja usando o CLDR.
Unicode na prática
Para quem escreve programas, a lição mais importante é simples: use
UTF-8 em todo lugar e diga isso explicitamente. Numa página web, o
cabeçalho deve começar com <meta charset="utf-8">. Num banco de dados,
escolha UTF-8 ao criar as tabelas. E ao ler ou gravar arquivos, informe
a codificação em vez de confiar no padrão do sistema, que muda de um
computador para outro. Em Python:
import unicodedata
texto = "Ação 👍🏽"
print(len(texto)) # 7: pontos de código, não grafemas
print(len(texto.encode("utf-8"))) # 15 bytes
print(hex(ord("ç"))) # 0xe7
print(unicodedata.name("ç")) # LATIN SMALL LETTER C WITH CEDILLA
a, b = "S\u00e3o", "Sa\u0303o" # til pronto e til combinante
print(a == b) # False
nfc = lambda s: unicodedata.normalize("NFC", s)
print(nfc(a) == nfc(b)) # True
with open("dados.txt", encoding="utf-8") as f:
conteudo = f.read()
A função len do Python conta pontos de código: “Ação 👍🏽” tem 7, porque
o polegar e o tom de pele contam como dois. O mesmo texto ocupa 15 bytes
em UTF-8. E as duas grafias de “São”, com o til pronto ou combinante, só
ficam iguais depois de normalizadas. No JavaScript, Array.from(texto)
separa um texto em pontos de código, texto.normalize("NFC") o
normaliza e Intl.Segmenter o separa em grafemas.
Algumas armadilhas são clássicas. No MySQL, a codificação chamada utf8
aceita no máximo 3 bytes por caractere e não guarda emojis; a versão
completa se chama utf8mb4. Muitos programas testados só com texto em
inglês falham com acentos, com emojis ou com árabe, e vale a pena
testá-los com os exemplos deste guia. E, quando o texto vem de fora,
como nomes de usuário ou endereços, é preciso lembrar que duas
sequências diferentes podem ter a mesma aparência.
E se faltar um caractere? Qualquer pessoa pode enviar uma proposta ao Consórcio Unicode. Para uma escrita nova, é preciso mostrar que ela é ou foi usada, com exemplos de documentos, e muitas propostas levam anos entre a pesquisa e a aprovação. Para um emoji novo, é preciso mostrar que ele seria muito usado. Hoje, boa parte do trabalho está nas escritas históricas e nas de povos minoritários, muitas ainda sem suporte nos computadores. Com o programa Adopt a Character, qualquer um pode “adotar” um caractere, e a doação ajuda a financiar esse trabalho.
Palavras finais
O Unicode é uma das infraestruturas mais bem-sucedidas da computação, e uma das menos visíveis. Ele resolveu um problema que parecia sem solução, o de fazer computadores do mundo todo concordarem sobre o significado de cada número, sem apagar a diversidade das escritas: das letras latinas aos hieróglifos, do árabe ao hangul, cada uma cabe no mesmo espaço, com as suas próprias regras.
Quase tudo o que ele pede de quem lida com texto é não presumir: nem que um caractere cabe num byte, nem que um ponto de código é uma letra, nem que o texto corre para a direita, nem que duas letras iguais na tela são iguais na memória. Da próxima vez que um “ç” aparecer no lugar de um “ç”, você saberá exatamente o que aconteceu: dois bytes de UTF-8 foram lidos, um a um, na tabela errada.
Leituras adicionais
- The Unicode Standard, Version 18.0 (2026), a versão atual do padrão, e as tabelas de códigos, com o desenho de referência de cada caractere.
- Os anexos técnicos sobre normalização (UAX #15), grafemas e segmentação de texto (UAX #29), o algoritmo bidirecional (UAX #9), ordenação (UTS #10) e segurança e caracteres confundíveis (UTS #39).
- RFC 3629: UTF-8, a transformation format of ISO 10646 (2003).
- Rob Pike, “UTF-8 history” (2003), o relato da noite no restaurante.
- Joseph D. Becker, “Unicode 88” (1988), a proposta original.
- Joel Spolsky, “The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets” (2003), um clássico para programadores.
- Nicholas Boucher e Ross Anderson, “Trojan Source: Invisible Vulnerabilities” (2021).
- Protocolo IP, Sistema DNS e HTTP e HTTPS, outros guias deste site.
Os dados do espaço de códigos e os nomes dos caracteres vêm do banco de dados de caracteres do Unicode 18.0; a divisão das escritas em regiões é uma simplificação. As operações de texto das figuras, como normalização, maiúsculas e ordenação, são feitas pelo seu próprio navegador, e a aparência dos caracteres depende das fontes instaladas no seu aparelho: se algum aparecer como um retângulo vazio, é tofu. Só o “g” serifado, o manuscrito e os ideogramas do painel dos glifos vêm de fontes servidas por este site, recortes da IBM Plex Serif, da Caveat, da Noto Sans SC e da Noto Sans JP. As estatísticas foram consultadas em setembro de 2026.