O que é Unicode, UTF-8, UTF-16?

Qual é a base para Unicode e por que a necessidade de UTF-8 ou UTF-16? Eu pesquisei isso no Google e procurei aqui também, mas não está claro para mim.

No VSS ao fazer uma comparação de arquivos, às vezes há uma mensagem dizendo que os dois arquivos têm UTFs diferentes. Por que isso seria o caso?

Por favor, explique em termos simples.

Por que precisamos do Unicode?

Nos (não muito) primeiros dias, tudo o que existia era ASCII. Tudo bem, já que 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 atual de intercomunicação global e mídia social não foi previsto, e não é muito incomum ver o inglês, العربية, 汉语, עִבְרִית, ελληνικά e ភាសាខ្មែរ no mesmo documento (espero não ter quebrado nenhum navegadores).

Mas, para argumentar, vamos dizer que Joe Average é um desenvolvedor de software. Ele insiste que só precisará do inglês e, como tal, só quer usar o ASCII. Isso pode ser bom para Joe, o usuário , mas isso não é bom para Joe, o desenvolvedor de software . Aproximadamente metade do mundo usa caracteres não-latinos e o uso de ASCII é indiscutivelmente desconsiderado para essas pessoas e, além disso, ele está fechando seu software para uma economia grande e em crescimento.

Portanto, um conjunto abrangente de caracteres incluindo todos os idiomas é necessário. Assim veio o Unicode. Ele atribui a cada caractere um número único 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 ​​é representada por apenas dois bytes, em uma região chamada Plano Multilíngue Básico (BMP) . Agora, uma codificação de caracteres é necessária para acessar esse conjunto de caracteres e, como a pergunta é feita, vou me concentrar em UTF-8 e UTF-16.

Considerações de memory

Quantos bytes dão access a quais caracteres nessas codificações?

  • UTF-8:
    • 1 byte: padrão ASCII
    • 2 bytes: árabe, hebraico, a maioria dos scripts europeus (mais notavelmente excluindo georgiano )
    • 3 bytes: BMP
    • 4 bytes: todos os caracteres Unicode
  • UTF-16:
    • 2 bytes: BMP
    • 4 bytes: todos os caracteres Unicode

Vale a pena mencionar agora que os caracteres 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, então o UTF-8 é certamente mais eficiente em termos de memory. No entanto, se você estiver trabalhando principalmente com scripts não europeus, o uso de UTF-8 pode ser até 1,5 vezes menos eficiente em termos de memory que o UTF-16. Ao lidar com grandes quantidades de texto, como grandes páginas da Web ou documentos longos, isso pode afetar o desempenho.

Noções básicas de codificação

Nota: Se você sabe 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 padrão ASCII (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-4 bytes. Isso é feito reservando alguns bits em cada um desses bytes para indicar que ele faz parte de um caractere de múltiplos bytes. Em particular, o primeiro bit de cada byte é 1 para evitar conflitos 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 porções de dois bytes é mapeada para um caractere não-BMP. Essas porções 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 tem dois bytes como sua unidade básica, ele é afetado pelo endianness . Para compensar, uma marca de ordem de byte reservada pode ser colocada no início de um stream de dados que indica endianness. Portanto, se você estiver lendo a input UTF-16 e nenhuma endianness for especificada, você deve verificar isso.

Como pode ser visto, UTF-8 e UTF-16 estão longe de serem compatíveis uns com os outros. Então, se você está fazendo I / O, certifique-se de saber qual codificação você está usando! Para mais detalhes sobre essas codificações, consulte as perguntas frequentes da UTF .

Considerações práticas de programação

Tipos de dados Character e String: 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 se o tipo de caractere for baseado em um UTF, isso não significa que as strings são adequadas para UTF. Eles podem permitir seqüências de bytes que são ilegais. Geralmente, você terá que usar uma biblioteca que suporte UTF, como ICU para C, C ++ e Java. Em qualquer caso, se você deseja inserir / enviar algo diferente da codificação padrão, será necessário 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, tem sido a codificação recomendada . Por outro lado, os ambientes .NET e Java são baseados em um tipo de caractere UTF-16. Confusamente (e incorretamente), referências são feitas frequentemente à “codificação Unicode”, que geralmente se refere à codificação UTF dominante em um determinado ambiente.

Suporte de biblioteca: Quais codificações são as bibliotecas que você está usando? 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, já que caracteres de 1, 2 e até 3 bytes podem ocorrer com frequência. No entanto, nem todas as bibliotecas UTF-16 supostamente suportam pares substitutos adequadamente, uma vez que 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 combinando) 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 por igualdade: A, А e Α parecem iguais, mas são latinos, cirílicos e gregos, respectivamente. Você também tem casos como C e Ⅽ, um é uma carta, o outro é um numeral romano. Além disso, temos os personagens combinados a serem considerados também. Para mais informações, consulte Caracteres duplicados em Unicode .

Pares substitutos: Eles surgem com frequência suficiente em SO, então apenas forneço alguns links de exemplo:

  • Obtendo o comprimento da string
  • Removendo pares substitutos
  • Verificação de palíndromo

Outras?:

  • Unicode
    • é um conjunto de caracteres usados ​​em todo o mundo
  • UTF-8
    • uma codificação de caracteres capaz de codificar todos os caracteres possíveis (chamados pontos de código) em Unicode.
    • unidade de código é de 8 bits
    • use um a quatro unidades de código para codificar Unicode
    • 00100100 para ” $ ” (um 8 bits); 11000010 10100010 para ” ¢ ” (dois 8 bits); 11100010 10000010 10101100 para ” ” (três 8 bits)
  • UTF-16
    • outra codificação de caracteres
    • unidade de código é de 16 bits
    • use uma ou duas unidades de código para codificar Unicode
    • 00000000 00100100 para ” $ ” (um 16 bits); 11011000 01010010 11011111 01100010 para ” 𤭢 ” (dois 16 bits)

Unicode é um padrão bastante complexo. Não tenha medo, mas esteja preparado para algum trabalho! [2]

Porque um recurso confiável é sempre necessário, mas o relatório oficial é enorme, sugiro ler o seguinte:

  1. O Mínimo Absoluto que Todo Desenvolvedor de Software Absolutamente, Positivamente Deve Saber Sobre Unicode e Conjuntos de Caracteres (Sem Desculpas!) Uma introdução de Joel Spolsky, CEO da Stack Exchange.
  2. Para o BMP e além! Um tutorial de Eric Muller, diretor técnico, depois, vice-presidente mais tarde, no The Unicode Consortium. (primeiros 20 slides e pronto)

Uma breve explicação:

Os computadores leem bytes e as pessoas lêem caracteres, por isso usamos padrões de codificação para mapear caracteres para bytes. ASCII foi o primeiro padrão amplamente utilizado, mas abrange apenas o latim (7 bits / caractere pode representar 128 caracteres diferentes). Unicode é um padrão com o objective de cobrir todos os caracteres possíveis no mundo (pode conter até 1.114.112 caracteres, o que significa um máximo de 21 bits / caracter. O Unicode 8.0 atual especifica 120.737 caracteres no total, e isso é tudo).

A principal diferença é que um caractere ASCII pode caber em um byte (8 bits), mas a maioria dos caracteres Unicode não pode. Então codificação de formulários / esquemas (como UTF-8 e UTF-16) são usados, e o modelo de personagem é assim:

Cada caractere contém uma posição enumerada de 0 a 1.114.111 (hexadecimal: 0-10FFFF) chamada ponto de código .
Um formulário de codificação mapeia um ponto de código para uma sequência de unidade de código. Uma unidade de código é a maneira que você deseja que os caracteres sejam organizados na memory, unidades de 8 bits, unidades de 16 bits e assim por diante. O UTF-8 usa de 1 a 4 unidades de 8 bits e o UTF-16 usa 1 ou 2 unidades de 16 bits para cobrir todo o Unicode de 21 bits no máximo. As unidades usam prefixos para que os limites dos caracteres possam ser vistos e mais unidades signifiquem mais prefixos que ocupam bits. Portanto, embora o UTF-8 use 1 byte para o script latino, ele precisa de 3 bytes para scripts posteriores dentro do Basic Multilingual Plane, enquanto o UTF-16 usa 2 bytes para todos eles. E essa é a principal diferença deles.
Por último, um esquema de codificação (como UTF-16BE ou UTF-16LE) mapeia (serializa) uma sequência de unidade de código para uma sequência de bytes.

personagem: π
ponto de código: U + 03C0
formulários de codificação (unidades de código):
UTF-8: CF 80
UTF-16: 03C0
esquemas de codificação (bytes):
UTF-8: CF 80
UTF-16BE: 03 C0
UTF-16LE: C0 03

Dica: um dígito hexadecimal representa 4 bits, portanto, um número hexadecimal de dois dígitos representa um byte
Também dê uma olhada nos mapas do Plane na Wikipedia para ter uma ideia do layout do conjunto de caracteres.

Originalmente, o Unicode pretendia ter uma codificação de 16 bits de largura fixa (UCS-2). Os primeiros usuários do Unicode, como o Java e o Windows NT, criaram suas bibliotecas em strings de 16 bits.

Mais tarde, o escopo do Unicode foi expandido para include caracteres históricos, o que exigiria mais do que os 65.536 pontos de código que uma codificação de 16 bits suportaria. Para permitir que os caracteres adicionais fossem representados em plataformas que usaram o UCS-2, a codificação UTF-16 foi introduzida. Ele usa “pares substitutos” para representar caracteres nos planos suplementares.

Enquanto isso, muitos softwares e protocolos de rede mais antigos usavam strings de 8 bits. O UTF-8 foi feito para que esses sistemas pudessem suportar o Unicode sem ter que usar caracteres largos. É compatível com versões anteriores do ASCII de 7 bits.

Porquê unicode? Porque ASCII tem apenas 127 caracteres. Aqueles de 128 a 255 diferem em diferentes países, é por isso que existem páginas de códigos. Então eles disseram que tem até 1114111 caracteres. Então, como você armazena o maior ponto de código? Você precisará armazená-lo usando 21 bits, então você usará um DWORD com 32 bits com 11 bits desperdiçados. Portanto, se você usar um DWORD para armazenar um caractere unicode, será a maneira mais fácil, porque o valor em seu DWORD corresponde exatamente ao ponto de código. Mas os arrays DWORD são obviamente maiores que os arrays do WORD e, claro, ainda maiores que os arrays BYTE. É por isso que não há apenas utf-32, mas também utf-16. Mas utf-16 significa um stream WORD, e um WORD tem 16 bits, então como o maior código 1114111 pode caber em um WORD? Eu não posso! Então eles colocam tudo mais alto que 65535 em um DWORD que eles chamam de um par substituto. Esse par substituto são duas palavras e podem ser detectados observando os primeiros 6 bits. Então e quanto ao utf-8? É uma matriz de bytes ou um stream de bytes, mas como o maior ponto de código 1114111 pode se encheckboxr em um byte? Eu não posso! Ok, então eles colocaram também um DWORD certo? Ou possivelmente uma palavra, certo? Quase certo! Eles inventaram as seqüências utf-8, o que significa que cada ponto de código maior que 127 deve ser codificado em uma sequência de 2 bytes, 3 bytes ou 4 bytes. Uau! Mas como podemos detectar essas seqüências? Bem, tudo até 127 é ASCII e é um único byte. O que começa com 110 é uma sequência de dois bytes, o que começa com 1110 é uma sequência de três bytes e o que começa com 11110 é uma sequência de quatro bytes. Os bits restantes desses chamados “startbytes” pertencem ao ponto de código. Agora, dependendo da seqüência, os seguintes bytes devem seguir. Um byte seguinte começa com 10, os bits restantes são 6 bits de bits de carga e pertencem ao ponto de código. Concatene os bits de carga do startbyte e do byte a seguir e você terá o codepoint. Essa é toda a magia do utf-8.

Este artigo explica todos os detalhes http://kunststube.net/encoding/

ESCREVER AO BUFFER

se você gravar em um buffer de 4 bytes, símbolo com codificação UTF8, seu binário ficará assim:

00000000 11100011 10000001 10000010

se você escrever para um buffer de 4 bytes, símbolo com codificação UTF16, seu binário ficará assim:

00000000 00000000 00110000 01000010

Como você pode ver, dependendo do idioma que você usaria em seu conteúdo, isso afetará sua memory de acordo.

Por exemplo, para este símbolo em particular: enc A codificação UTF16 é mais eficiente, pois temos 2 bytes extras para usar no próximo símbolo. Mas isso não significa que você deve usar o alfabeto UTF16 para o Japão.

LEITURA DO BUFFER

Agora, se você quiser ler os bytes acima, você deve saber em qual codificação ele foi gravado e decodificá-lo corretamente.

Por exemplo, se você decodificar isto: 00000000 11100011 10000001 10000010 na codificação UTF16, você acabará com não

Nota: Codificação e Unicode são duas coisas diferentes. Unicode é o grande (tabela) com cada símbolo mapeado para um único ponto de código. Por exemplo, o símbolo ((letra) tem um (ponto de código) : 30 42 (hex). A codificação, por outro lado, é um algoritmo que converte símbolos de maneira mais apropriada, ao armazenar em hardware.

 30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary. 30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary. 

insira a descrição da imagem aqui

Unicode é um padrão que mapeia os caracteres em todos os idiomas para um valor numérico específico chamado Pontos de Código . A razão disso é porque permite que diferentes codificações sejam possíveis usando o mesmo conjunto de pontos de código.

UTF-8 e UTF-16 são duas dessas codificações. Eles pegam pontos de código como input e os codificam usando alguma fórmula bem definida para produzir a string codificada.

A escolha de uma codificação específica depende dos seus requisitos. Codificações diferentes têm requisitos de memory diferentes e, dependendo dos caracteres com os quais você estará lidando, você deve escolher a codificação que usa menos seqüências de bytes para codificar esses caracteres.

Para detalhes mais detalhados sobre Unicode, UTF-8 e UTF-16, você pode conferir este artigo,

O que todo programador deve saber sobre o Unicode

UTF significa stands para Unicode Transformation Format. Basicamente, no mundo de hoje existem scripts escritos em centenas de outras linguagens, formatos não cobertos pelo ASCII básico usado anteriormente. Assim, a UTF passou a existir.

UTF-8 tem capacidades de codificação de caracteres e sua unidade de código é de 8 bits, enquanto que para UTF-16 é de 16 bits.