Quantos bytes um caractere Unicode usa?

Estou um pouco confuso sobre codificações. Até onde sei, caracteres ASCII antigos recebiam um byte por caractere. Quantos bytes um caractere Unicode requer?

Eu suponho que um caractere Unicode pode conter todos os caracteres possíveis de qualquer idioma – estou correto? Quantos bytes precisa por caractere?

E o que significam UTF-7, UTF-6, UTF-16 etc. São versões diferentes do Unicode?

Eu li o artigo da Wikipedia sobre Unicode, mas é bastante difícil para mim. Estou ansioso para ver uma resposta simples.

Você não verá uma resposta simples porque não há uma.

Primeiro, o Unicode não contém “todos os caracteres de todas as linguagens”, embora certamente tente.

O próprio Unicode é um mapeamento, define pontos de código e um ponto de código é um número, geralmente associado a um caractere. Eu digo geralmente porque existem conceitos como combinar caracteres. Você pode estar familiarizado com coisas como acentos ou umlauts. Podem ser usados ​​com outro caractere, como a ou a para criar um novo caractere lógico. Um caractere, portanto, pode consistir em 1 ou mais pontos de código.

Para ser útil em sistemas de computação, precisamos escolher uma representação para essa informação. Essas são as várias codificações unicode, como utf-8, utf-16le, utf-32, etc. Elas são amplamente diferenciadas pelo tamanho de suas codeunits. O UTF-32 é a codificação mais simples, ele tem uma codeunit que é de 32bits, o que significa que um codepoint individual se encheckbox confortavelmente em uma codeunit. As outras codificações terão situações em que um codepoint precisará de várias codeunits, ou esse codepoint específico não pode ser representado na codificação (isso é um problema, por exemplo, com o UCS-2).

Devido à flexibilidade de combinar caracteres, mesmo dentro de uma determinada codificação, o número de bytes por caractere pode variar dependendo do caractere e do formulário de normalização. Este é um protocolo para lidar com caracteres que têm mais de uma representação (você pode dizer "an 'a' with an accent" que é 2 pontos de código, um dos quais é um caractere de combinação ou "accented 'a'" ).

Estranhamente, ninguém apontou como calcular quantos bytes está tomando um caractere Unicode. Aqui está a regra para strings codificadas em UTF-8:

 Binary Hex Comments 0xxxxxxx 0x00..0x7F Only byte of a 1-byte character encoding 10xxxxxx 0x80..0xBF Continuation bytes (1-3 continuation bytes) 110xxxxx 0xC0..0xDF First byte of a 2-byte character encoding 1110xxxx 0xE0..0xEF First byte of a 3-byte character encoding 11110xxx 0xF0..0xF4 First byte of a 4-byte character encoding 

Portanto, a resposta rápida é: leva de 1 a 4 bytes, dependendo do primeiro que irá indicar quantos bytes ele irá ocupar.

Atualizar

Como prewett apontou, esta regra só se aplica a UTF-8

Eu sei que esta pergunta é antiga e já tem uma resposta aceita, mas eu quero oferecer alguns exemplos (esperando que seja útil para alguém).

Até onde sei, caracteres ASCII antigos recebiam um byte por caractere.

Certo. Na verdade, como o ASCII é uma codificação de 7 bits, ele suporta 128 códigos (95 dos quais são imprimíveis), portanto, ele usa apenas meio byte (se isso fizer algum sentido).

Quantos bytes um caractere Unicode requer?

O Unicode apenas mapeia caracteres para pontos de código. Não define como codificá-los. Um arquivo de texto não contém caracteres Unicode, mas bytes / octetos que podem representar caracteres Unicode.

Eu suponho que um caractere Unicode pode conter todos os caracteres possíveis de qualquer idioma – estou correto?

Não. Mas quase. Então, basicamente sim. Mas ainda não.

Quantos bytes precisa por caractere?

O mesmo que a sua segunda pergunta.

E o que significa UTF-7, UTF-6, UTF-16 etc? Eles são algum tipo de versões Unicode?

Não, essas são codificações. Eles definem como bytes / octetos devem representar caracteres Unicode.

Um par de exemplos. Se alguns deles não puderem ser exibidos em seu navegador (provavelmente porque a fonte não os suporta), vá para http://codepoints.net/U+1F6AA (substitua 1F6AA pelo ponto de código em hexadecimal) para ver uma imagem.

    • U + 0061 LETRA PEQUENA A: a
      • Nº: 97
      • UTF-8: 61
      • UTF-16: 00 61
    • SINAL © COPYRIGHT © U + 00A9: ©
      • Nº: 169
      • UTF-8: C2 A9
      • UTF-16: 00 A9
    • U + 00AE SINAL REGISTRADO: ®
      • Nº 174
      • UTF-8: C2 AE
      • UTF-16: 00 AE
    • U + 1337 ETHIOPIC SYLLABLE PHWA:
      • Nº: 4919
      • UTF-8: E1 8C B7
      • UTF-16: 13 37
    • U + 2014 EM DASH:
      • Nº: 8212
      • UTF-8: E2 80 94
      • UTF-16: 20 14
    • U + 2030 POR SINAL DE MILLE:
      • Nº: 8240
      • UTF-8: E2 80 B0
      • UTF-16: 20 30
    • SINAL DO EURO DE U + 20AC:
      • Nº: 8364
      • UTF-8: E2 82 AC
      • UTF-16: 20 AC
    • U + 2122 SINAL DE MARCA COMERCIAL:
      • Nº: 8482
      • UTF-8: E2 84 A2
      • UTF-16: 21 22
    • U + 2603 BONECO DE NEVE:
      • Nº: 9731
      • UTF-8: E2 98 83
      • UTF-16: 26 03
    • U + 260E TELEFONE PRETO:
      • Nº: 9742
      • UTF-8: E2 98 8E
      • UTF-16: 26 0E
    • U + 2614 GUARDA-CHUVA COM GOTAS DE CHUVA:
      • Nº: 9748
      • UTF-8: E2 98 94
      • UTF-16: 26 14
    • CARA DE SORRISO BRANCO U + 263A:
      • Nº: 9786
      • UTF-8: E2 98 BA
      • UTF-16: 26 3A
    • U + 2691 BANDEIRA PRETA:
      • Nº: 9873
      • UTF-8: E2 9A 91
      • UTF-16: 26 91
    • U + 269B SÍMBOLO ATOM:
      • Nº: 9883
      • UTF-8: E2 9A 9B
      • UTF-16: 26 9B
    • U + 2708 AVIÃO:
      • Nº: 9992
      • UTF-8: E2 9C 88
      • UTF-16: 27 08
    • U + 271E CRUZ LATIN BRANCA SOMBRADA:
      • Nº: 10014
      • UTF-8: E2 9C 9E
      • UTF-16: 27 1E
    • FACE DE MARCA POSTAL U + 3020:
      • Nº: 12320
      • UTF-8: E3 80 A0
      • UTF-16: 30 20
    • U + 8089 CJK IDEOGRAPH-8089 UNIFICADO:
      • Nº: 32905
      • UTF-8: E8 82 89
      • UTF-16: 80 89
    • U + 1F4A9 PILHA DE POO: 💩
      • Nº: 128169
      • UTF-8: F0 9F 92 A9
      • UTF-16: D8 3D DC A9
    • U + 1F680 ROCKET: 🚀
      • Nº: 128640
      • UTF-8: F0 9F 9A 80
      • UTF-16: D8 3D DE 80

Ok, eu estou me empolgando …

Curiosidades:

  • Se você está procurando por um personagem específico, copie e cole em http://codepoints.net/ .
  • Eu perdi muito tempo nesta lista inútil (mas está ordenada!).
  • O MySQL tem um conjunto de caracteres chamado “utf8” que na verdade não suporta caracteres maiores que 3 bytes. Então você não pode inserir uma pilha de cocô , o campo será silenciosamente truncado. Use “utf8mb4” em seu lugar.
  • Há uma página de teste de boneco de neve (unicodesnowmanforyou.com) .

Simplesmente falando Unicode é um padrão que atribuiu um número (chamado ponto de código) a todos os caracteres do mundo (ele ainda está em andamento).

Agora você precisa representar esses pontos de código usando bytes, isso é chamado de character encoding . UTF-8, UTF-16, UTF-6 são formas de representar esses caracteres.

UTF-8 é uma codificação de caracteres multibyte. Os caracteres podem ter de 1 a 6 bytes (alguns deles podem não ser necessários agora).

UTF-32 cada caractere tem 4 bytes por caractere.

UTF-16 usa 16 bits para cada caractere e representa apenas parte dos caracteres Unicode chamados BMP (para todos os fins práticos é suficiente). Java usa essa codificação em suas strings.

Em Unicode, a resposta não é dada facilmente. O problema, como você já apontou, são as codificações.

Dada qualquer sentença em inglês sem caracteres diacríticos, a resposta para UTF-8 seria tantos bytes quanto caracteres e para UTF-16 seria número de caracteres vezes dois.

A única codificação em que (até agora) podemos fazer a declaração sobre o tamanho é UTF-32. Há sempre 32 bits por caractere, embora eu imagine que os pontos de código estejam preparados para um futuro UTF-64 🙂

O que torna isso tão difícil são pelo menos duas coisas:

  1. caracteres compostos, onde, em vez de usar a entidade de caractere que já é acentuada / diacrítica (À), um usuário decidiu combinar o acento e o caractere base (`A).
  2. pontos de código. Os pontos de código são o método pelo qual as codificações em UTF permitem codificar mais do que o número de bits que lhes dá seu nome normalmente permitiriam. Por exemplo, o UTF-8 designa certos bytes que por si próprios são inválidos, mas quando seguidos por um byte de continuação válido permitirá descrever um caractere além do intervalo de 8 bits de 0..255. Veja os Exemplos e as Codificações Overlong abaixo no artigo da Wikipedia sobre UTF-8.
    • O excelente exemplo dado lá é que o caractere € (o ponto de código U+20AC pode ser representado como sequência de três bytes E2 82 AC ou sequência de quatro bytes F0 82 82 AC .
    • Ambos são válidos, e isso mostra como a resposta é complicada quando se fala de “Unicode” e não sobre uma codificação específica de Unicode, como UTF-8 ou UTF-16.

Em UTF-8:

 1 byte: 0 - 7F (ASCII) 2 bytes: 80 - 7FF (all European plus some Middle Eastern) 3 bytes: 800 - FFFF (multilingual plane incl. the top 1792 and private-use) 4 bytes: 10000 - 10FFFF 

Em UTF-16:

 2 bytes: 0 - D7FF (multilingual plane except the top 1792 and private-use ) 4 bytes: D800 - 10FFFF 

Em UTF-32:

 4 bytes: 0 - 10FFFF 

10FFFF é o último ponto de código unicode por definição, e é definido dessa forma porque é o limite técnico do UTF-16.

É também o maior codepoint que o UTF-8 pode codificar em 4 bytes, mas a idéia por trás da codificação do UTF-8 também funciona para codificações de 5 e 6 bytes para cobrir os pontos de código até 7FFFFFFF, ie. metade do que o UTF-32 pode.

Existe uma ótima ferramenta para calcular os bytes de qualquer string em UTF-8: http://mothereff.in/byte-counter

Atualização: @mathias tornou o código público: https://github.com/mathiasbynens/mothereff.in/blob/master/byte-counter/eff.js

Bem, eu apenas abri a página da Wikipedia sobre isso também, e na parte de introdução vi “Unicode pode ser implementado por diferentes codificações de caracteres. As codificações mais usadas são UTF-8 (que usa um byte para qualquer caractere ASCII, que tem os mesmos valores de código na codificação UTF-8 e ASCII e até quatro bytes para outros caracteres), o UCS-2 agora obsoleto (que usa dois bytes para cada caractere, mas não pode codificar cada caractere no padrão Unicode atual) ”

Como esta citação demonstra, seu problema é que você está assumindo que o Unicode é uma maneira única de codificar caracteres. Na verdade, existem várias formas de Unicode e, novamente nessa citação, uma delas tem até 1 byte por caractere, exatamente como você está acostumado.

Então, sua resposta simples que você quer é que isso varia.

Para UTF-16, o caractere precisa de quatro bytes (duas unidades de código) se iniciar com 0xD800 ou superior; tal personagem é chamado de “par substituto”. Mais especificamente, um par substituto tem a forma:

 [0xD800 - 0xDBFF] [0xDC00 - 0xDFF] 

onde […] indica uma unidade de código de dois bytes com o intervalo dado. Qualquer coisa < = 0xD7FF é uma unidade de código (dois bytes). Qualquer coisa> = 0xE000 é inválida (exceto marcadores BOM, discutivelmente).

Veja http://unicodebook.readthedocs.io/unicode_encodings.html , seção 7.5.

Confira este conversor de código Unicode . Por exemplo, digite 0x2009 , em que 2009 é o número Unicode para o espaço thin , no campo “0x … notation” e clique em Convert. O número hexadecimal E2 80 89 (3 bytes) aparece no campo “Unidades de código UTF-8”.