Diferença entre UTF-8 e UTF-16?

137

Diferença entre UTF-8 e UTF-16? Por que precisamos disso?

MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "This is some text";

md.update(text.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
theJava
fonte
2
jon skeet tem um bom artigo sobre codificação .... csharpindepth.com/Articles/General/Unicode.aspx
Mitch Wheat

Respostas:

284

Acredito que existem muitos bons artigos sobre isso na Web, mas aqui está um breve resumo.

UTF-8 e UTF-16 são codificações de comprimento variável. No entanto, em UTF-8, um caractere pode ocupar um mínimo de 8 bits, enquanto em UTF-16 o comprimento de caractere começa com 16 bits.

Principais profissionais do UTF-8:

  • Caracteres ASCII básicos, como dígitos, caracteres latinos sem acentos, etc. ocupam um byte idêntico à representação US-ASCII. Dessa forma, todas as seqüências US-ASCII se tornam UTF-8 válidas, o que fornece compatibilidade retroativa decente em muitos casos.
  • Sem bytes nulos, que permitem usar cadeias terminadas em nulo, isso também introduz uma grande compatibilidade com versões anteriores.
  • O UTF-8 é independente da ordem dos bytes, portanto você não precisa se preocupar com o problema do Big Endian / Little Endian.

Principais contras UTF-8:

  • Muitos caracteres comuns têm comprimento diferente, o que diminui a indexação por ponto de código e calcula terrivelmente a contagem de pontos de código.
  • Mesmo que a ordem dos bytes não importe, algumas vezes o UTF-8 ainda possui BOM (marca de ordem dos bytes), que serve para notificar que o texto está codificado em UTF-8 e também quebra a compatibilidade com o software ASCII, mesmo que o texto contenha apenas caracteres ASCII . O software da Microsoft (como o Bloco de notas) gosta especialmente de adicionar BOM ao UTF-8.

Principais profissionais do UTF-16:

  • Caracteres BMP (plano multilíngüe básico), incluindo latim, cirílico, a maioria dos chineses (a RPC fez o suporte a alguns pontos de código fora do BMP obrigatório), a maioria dos japoneses pode ser representada com 2 bytes. Isso acelera a indexação e o cálculo da contagem de pontos de código, caso o texto não contenha caracteres adicionais.
  • Mesmo se o texto tiver caracteres suplementares, eles ainda serão representados por pares de valores de 16 bits, o que significa que o comprimento total ainda é divisível por dois e permite usar 16 bits charcomo o componente primitivo da string.

Principais contras UTF-16:

  • Muitos bytes nulos em cadeias US-ASCII, o que significa que não há cadeias terminadas em nulo e muita memória desperdiçada.
  • Usá-lo como uma codificação de comprimento fixo “funciona principalmente” em muitos cenários comuns (especialmente nos EUA / UE / países com alfabetos cirílicos / Israel / países árabes / Irã e muitos outros), geralmente levando a um suporte quebrado onde não funciona. Isso significa que os programadores devem estar cientes dos pares substitutos e manipulá-los adequadamente nos casos em que isso importa!
  • Seu comprimento é variável, portanto, contar ou indexar pontos de código é caro, embora menor que UTF-8.

Em geral, o UTF-16 geralmente é melhor para a representação na memória porque o BE / LE é irrelevante lá (basta usar a ordem nativa) e a indexação é mais rápida (apenas não se esqueça de lidar adequadamente com pares substitutos). O UTF-8, por outro lado, é extremamente bom para arquivos de texto e protocolos de rede, porque não há problema de BE / LE e a terminação nula geralmente é útil, além de compatibilidade com ASCII.

Sergei Tachenov
fonte
3
Faltam apenas BE / LE parte em UTF16 :) UTF-8 tem outra desvantagem, ele pode gerar mais saída do que UTF16
bestsss
4
Sim, eu esqueci o BE / LE. Porém, não é grande coisa, especialmente para uso na memória. O UTF-8 gerará uma saída mais longa apenas se caracteres de três bytes estiverem envolvidos, mas isso significa principalmente chinês e japonês. Por outro lado, se o texto contiver muitos caracteres US-ASCII, ele poderá gerar uma saída mais curta; portanto, se é uma desvantagem ou não, depende de uma situação específica.
Sergei Tachenov
Eu nem pensei em mencionar o profissional imediato do utf-8, menor. Sobre a saída mais longa do utf-8, foi 'may' por um motivo, mas se o destino estiver no extremo leste, a codificação padrão deve ser utf-16. Como no exemplo md.update (text.getBytes ("UTF-8")); a codificação não importa, pois o hash é estável nos dois sentidos.
bestsss 11/01
A maneira mais rápida de converter uma string em um array de bytes é algo assim, publicado como exemplo
bestsss
Você diz que os caracteres têm comprimento diferente em UTF-8, por isso diminui a indexação e o cálculo, mas duvido que os caracteres em UTF-16 também tenham comprimento diferente. A indexação e o cálculo do comprimento de UTF-16 devem ser mais rápidos?
31414 Nicky_zs
19

Eles são simplesmente esquemas diferentes para representar caracteres Unicode.

Ambos são de comprimento variável - o UTF-16 usa 2 bytes para todos os caracteres no plano multilíngue básico (BMP), que contém a maioria dos caracteres em uso comum.

O UTF-8 usa entre 1 e 3 bytes para caracteres no BMP, até 4 para caracteres no intervalo Unicode atual de U + 0000 a U + 1FFFFF e é extensível até U + 7FFFFFFF, se isso for necessário ... mas notavelmente todos os caracteres ASCII são representados em um único byte cada.

Para os propósitos de um resumo da mensagem, não importa qual deles você escolhe, desde que todos que tentam recriar o resumo usem a mesma opção.

Consulte esta página para obter mais informações sobre UTF-8 e Unicode.

(Observe que todos os caracteres Java são pontos de código UTF-16 no BMP; para representar caracteres acima de U + FFFF, é necessário usar pares substitutos em Java.)

Jon Skeet
fonte
5

Segurança: Use apenas UTF-8

Diferença entre UTF-8 e UTF-16? Por que precisamos disso?

Houve pelo menos algumas vulnerabilidades de segurança nas implementações do UTF-16 . Veja a Wikipedia para detalhes .

WHATWG e W3C têm agora declarou que só UTF-8 é para ser usado na Web.

Os problemas de [segurança] descritos aqui desaparecem ao usar exclusivamente UTF-8, que é uma das muitas razões que agora é a codificação obrigatória para todas as coisas.

Outros grupos estão dizendo o mesmo.

Portanto, embora o UTF-16 possa continuar sendo usado internamente por alguns sistemas como Java e Windows, o pouco uso do UTF-16 que você já viu no passado para arquivos de dados, troca de dados e outros provavelmente desaparecerá completamente.

Basil Bourque
fonte
4

Isso não está relacionado ao UTF-8/16 (em geral, embora ele converta em UTF16 e a parte BE / LE possa ser definida com uma única linha), mas abaixo é a maneira mais rápida de converter String em byte []. Por exemplo: bom exatamente para o caso fornecido (código hash). String.getBytes (enc) é relativamente lento.

static byte[] toBytes(String s){
        byte[] b=new byte[s.length()*2];
        ByteBuffer.wrap(b).asCharBuffer().put(s);
        return b;
    }
bestsss
fonte
-2

A maneira simples de diferenciar UTF-8 e UTF-16 é identificar pontos em comum entre eles.

Além de compartilhar o mesmo número unicode para um determinado caractere, cada um tem seu próprio formato.

Venkateswara Rao
fonte