Por que precisamos de Unicode?
Nos (não muito) primeiros dias, tudo o que existia era ASCII. Tudo bem, pois tudo o que seria necessário eram alguns caracteres de controle, pontuação, números e letras como os desta frase. Infelizmente, o estranho mundo da intercomunicação global e das mídias sociais de hoje não estava previsto, e não é incomum ver Inglês, العربية, 汉语, עִבְרִית, ελληνικά e ភាសាខ្មែរ no mesmo documento (espero não ter quebrado nenhum velho navegadores).
Mas, por uma questão de argumento, digamos que Joe Average é desenvolvedor de software. Ele insiste que só precisará usar o inglês e, como tal, só quer usar o ASCII. Isso pode ser bom para Joe, o usuário , mas não é bom para Joe, o desenvolvedor de software . Aproximadamente metade do mundo usa caracteres não latinos e o uso de ASCII é indiscutível para essas pessoas; além disso, ele está fechando seu software para uma economia grande e crescente.
Portanto, é necessário um conjunto de caracteres abrangente, incluindo todos os idiomas. Assim veio o Unicode. Ele atribui a cada caractere um número exclusivo chamado ponto de código . Uma vantagem do Unicode sobre outros conjuntos possíveis é que os primeiros 256 pontos de código são idênticos ao ISO-8859-1 e, portanto, também ao ASCII. Além disso, a grande maioria dos caracteres comumente usados é representável por apenas dois bytes, em uma região chamada BMP (Basic Multilingual Plane) . Agora é necessária uma codificação de caracteres para acessar esse conjunto de caracteres e, conforme a pergunta, vou me concentrar em UTF-8 e UTF-16.
Considerações sobre memória
Então, quantos bytes dão acesso a quais caracteres nessas codificações?
- UTF-8:
- 1 byte: ASCII padrão
- 2 bytes: árabe, hebraico, a maioria dos scripts europeus (principalmente os georgianos )
- 3 bytes: BMP
- 4 bytes: todos os caracteres Unicode
- UTF-16:
- 2 bytes: BMP
- 4 bytes: todos os caracteres Unicode
Vale ressaltar agora que os personagens que não estão no BMP incluem scripts antigos, símbolos matemáticos, símbolos musicais e caracteres chineses / japoneses / coreanos (CJK) mais raros .
Se você estiver trabalhando principalmente com caracteres ASCII, o UTF-8 certamente será mais eficiente em termos de memória. No entanto, se você estiver trabalhando principalmente com scripts não europeus, o uso de UTF-8 pode ter até 1,5 vezes menos eficiência de memória que o UTF-16. Ao lidar com grandes quantidades de texto, como páginas da Web grandes ou documentos extensos do Word, isso pode afetar o desempenho.
Noções básicas de codificação
Nota: Se você souber como UTF-8 e UTF-16 são codificados, pule para a próxima seção para aplicações práticas.
- UTF-8: Para os caracteres ASCII padrão (0-127), os códigos UTF-8 são idênticos. Isso torna o UTF-8 ideal se a compatibilidade com versões anteriores for necessária com o texto ASCII existente. Outros caracteres requerem de 2 a 4 bytes. Isso é feito reservando alguns bits em cada um desses bytes para indicar que faz parte de um caractere de vários bytes. Em particular, o primeiro bit de cada byte é
1
evitar colidir com os caracteres ASCII.
- UTF-16: Para caracteres BMP válidos, a representação UTF-16 é simplesmente seu ponto de código. No entanto, para caracteres não BMP, o UTF-16 introduz pares substitutos . Nesse caso, uma combinação de duas partes de dois bytes é mapeada para um caractere não BMP. Essas partes de dois bytes vêm do intervalo numérico BMP, mas são garantidas pelo padrão Unicode como inválidas como caracteres BMP. Além disso, como o UTF-16 possui dois bytes como unidade básica, ele é afetado pela resistência . Para compensar, uma marca de ordem de bytes reservada pode ser colocada no início de um fluxo de dados que indica endianness. Portanto, se você estiver lendo a entrada UTF-16 e nenhuma endianness for especificada, deverá verificar isso.
Como pode ser visto, UTF-8 e UTF-16 não são nem de longe compatíveis entre si. Portanto, se você estiver executando E / S, saiba qual codificação está usando! Para mais detalhes sobre essas codificações, consulte as Perguntas frequentes sobre UTF .
Considerações práticas de programação
Tipos de dados de caracteres e seqüências de caracteres: como eles são codificados na linguagem de programação? Se forem bytes brutos, no minuto em que você tentar gerar caracteres não ASCII, poderá ter alguns problemas. Além disso, mesmo que o tipo de caractere seja baseado em uma UTF, isso não significa que as seqüências de caracteres sejam UTF adequadas. Eles podem permitir seqüências de bytes ilegais. Geralmente, você precisará usar uma biblioteca que suporte UTF, como ICU para C, C ++ e Java. De qualquer forma, se você deseja inserir / produzir algo diferente da codificação padrão, precisará convertê-lo primeiro.
Codificações recomendadas / padrão / dominantes: quando é possível escolher qual UTF usar, geralmente é melhor seguir os padrões recomendados para o ambiente em que você está trabalhando. Por exemplo, o UTF-8 é dominante na web e, desde o HTML5, ele foi a codificação recomendada . Por outro lado, os ambientes .NET e Java são baseados em um tipo de caractere UTF-16. De maneira confusa (e incorreta), frequentemente são feitas referências à "codificação Unicode", que geralmente se refere à codificação UTF dominante em um determinado ambiente.
Suporte de biblioteca: as bibliotecas que você está usando suportam algum tipo de codificação. Qual? Eles suportam os casos de canto? Como a necessidade é a mãe da invenção, as bibliotecas UTF-8 geralmente suportam caracteres de 4 bytes corretamente, pois caracteres de 1, 2 e até 3 bytes podem ocorrer com freqüência. No entanto, nem todas as supostas bibliotecas UTF-16 suportam pares substitutos corretamente, pois ocorrem muito raramente.
Contando caracteres: Existem caracteres combinados em Unicode. Por exemplo, o ponto de código U + 006E (n) e U + 0303 (um til de combinação) formam ñ, mas o ponto de código U + 00F1 forma ñ. Eles devem parecer idênticos, mas um algoritmo de contagem simples retornará 2 para o primeiro exemplo, 1 para o último. Isso não é necessariamente errado, mas também pode não ser o resultado desejado.
Comparando para igualdade: A, А e Α têm a mesma aparência, mas são latim, cirílico e grego, respectivamente. Você também tem casos como C e Ⅽ, um é uma letra e o outro, um número romano. Além disso, também temos os caracteres combinados a serem considerados. Para mais informações, consulte Caracteres duplicados em Unicode .
Pares substitutos: eles surgem com frequência suficiente no SO, então fornecerei alguns exemplos de links:
Outras?: