Minicurso encoding

Preview:

DESCRIPTION

Você já perdeu a cabeça e a paciência tentando entender de onde vêm aqueles caracteres malignos que misteriosamente tomam o lugar das palavras acentuadas?Você não se conforma que o ser humano já foi pra lua mas ainda não conseguiu garantir que um mísero texto chegue corretamente ao seu destino?Você não entende o que diabo é Unicode, LATIN-1, UTF-8, UTF-16, UTF-32 e como essas coisas influenciam a sua vida?Seus problemas acabaram!! - ou não... Na verdade, eles vão continuar. Mas pelo menos você vai aprender a lidar melhor com eles!Neste minicurso, serão explicados os conceitos básicos do mundo mágico do encoding e da representação dos diferentes caracteres ao redor do mundo. Veremos por que motivos as coisas podem ficar feias e o que podemos fazer para elas ficarem bonitas. Veremos maneiras de programar defensivamente para evitar, dentro do possível, o infeliz problema.Compareçam!

Citation preview

Encoding em aplicaçõesAndré Willik Valenti

Dextra Sistemas

Roteiro▒ Parte 1

▒ O que é e por que existe

▒ Parte 2▒ Como funciona▒ Por que dá errado

▒ Parte 3▒ Como faz pra dar certo

Parte 1

O que é e por que existe

O que é encoding?▒ Mais especificamente:

▒ Character encoding

▒ Também conhecido como:▒ Codificação de caracteres▒ Charset

Quem é o encoding?▒ O encoding é o culpado por:

▒ Programação Programação Programa褯

▒ José Luís Assunção Júnior José Luís Assunção Júnior Jos題 u Assun 褯 J r�

Encoding▒ Por que se usa encoding?

▒ Onde NÃO se usa encoding?▒ Segure essa ideia!

▒ Computador é uma máquina de armazenar e processar informação▒ Mas o que É informação?▒ Segure essa ideia!

O que é isto?

O que era aquilo?▒ Pedras?▒ Ovos?▒ Feijões brancos?▒ Glóbulos brancos?

O que era aquilo?▒ Resposta:

▒ Depende de interpretação

▒ Seu cérebro recebeu estímulos visuais (dados) e interpretou alguma coisa (informação)

O que era aquilo?

Estímulos visuais (dados)

Processamento

Interpretação (informação)

O que era aquilo?▒ Os mesmos dados deram origem a informações diferentes

▒ Vamos voltar à imagem em si

O que era aquilo?▒ Aquela era uma imagem JPEG. Mas o que seria uma imagem JPEG?

Uma imagem mesmo?

Um monte de pixels?

Um monte de bytes?

Um grande número binário?

1111111111011000111111111110000000000000000100000100101001000110100100101000110000000000000000100000001000000010000000001011111

...

O que era aquilo?▒ A resposta correta é:

▒ Todas são diferentes formas de enxergar a mesma coisa

O que era aquilo?▒ A imagem é uma informação

▒ Pixels, bytes e bits são dados

▒ Dados são concretos. Informação é abstrata.

▒ Informação = dados + forma de interpretá­los

Informação=

dados + formade interpretá-los

Resumindo▒ Informação

▒ O conceito abstrato a ser representado▒ Exemplo: imagem

▒ Dados▒ Representação concreta de informação▒ Exemplo: sequência de bytes

▒ Encoding▒ Forma de codificar informação em dados▒ Exemplo: JPEG

Encoding▒ Voltando à pergunta: onde NÃO usa encoding?▒ Em lugar nenhum. Tudo usa encoding!

Encoding▒ PNG é um encoding▒ JPEG é um encoding▒ MPEG é um encoding▒ MP3 é um encoding▒ PDF é um encoding▒ ...

▒ Alguém já usou algum CODEC?

Character encoding▒ Um character encoding é uma determinada maneira de se representar caracteres

▒ Para refletir:▒ Como se representam caracteres?▒ É fácil representar caracteres?▒ TXT é um encoding?

Parte 2

Como (não) funciona

Por que dá errado

História▒ Década de 60

▒ Mais de 60 maneiras diferentes de representar caracteres

▒ Cada fabricante implementava do seu jeito

História▒ Bob Bemer:

▒ “Vamos uniformizar esse negócio...”

▒ Formou­se um comitê do ANSI (American National Standards Institute) para essa tarefa

▒ 2 anos de trabalho depois...

ASCII▒ American Standard Code for Information Interchange

▒ 7 bits

▒ 128 diferentes caracteres

ASCII▒ 0 – 31: controle

▒ Nulo▒ Início da transmissão▒ Quebra de linha

▒ 32 – 127: imprimíveis▒ Letras▒ Números▒ Símbolos

ASCII▒ Exemplos:

ASCII Decimal Hexa Binário

5 53 0x35 0110101

A 65 0x41 1000001

} 125 0x7D 1111101

ASCII▒ Intervalo válido

▒ Em binário: 0000000 – 1111111▒ Em hexadecimal: 0x00 – 0x7F

ASCII▒ Agora é só todo mundo começar a usar ASCII e jamais teremos problemas com caracteres novamente

▒ Tudo resolvido!

ASCII▒ Sabe que não...

ASCII▒ Em vez de usar apenas 7 bits, muitas máquinas usavam/usam 8

▒ E esse bit a mais aí?▒ Mantém sempre 0

ou▒ Usa como verificador de paridade

ASCII▒ Ou melhor ainda!! Vamos fazer o seguinte:

▒ Sabe esse oitavo bit aí que tá sobrando?

▒ Vamos usar pra codificar caracteres locais de cada país!

Extensões para ASCII▒ Codepages

▒ 437 — The original IBM PC code page▒ 720 — Arabic▒ 737 — Greek▒ 775 — Estonian, Lithuanian and Latvian

▒ 850 — "Multilingual (Latin­1)" (Western European languages)

Extensões para ASCII▒ Codepages

▒ 852 — "Slavic (Latin­2)" (Central and Eastern European languages)

▒ 855 — Cyrillic▒ 857 — Turkish▒ 858 — "Multilingual" with euro symbol▒ 860 — Portuguese

Extensões para ASCII▒ Codepages

▒ 863 — French (Quebec French) ▒ 865 — Danish/Norwegian▒ 866 — Cyrillic ▒ 869 — Greek ▒ 874 — Thai

ASCII▒ Maravilha! Com dezenas de encodings diferentes, todos poderão representar seus caracteres!

▒ Mas e a interoperabilidade?▒ Oras, quem é que vai precisar ler ou escrever usando caracteres dos outros países??

▒ O resultado todos já conhecem:

ASCII▒ No fim das contas, ficou assim:

▒ 0x00 – 0x7F: ASCII normal▒ 0x80 – 0xFF: ASCII estendido

ASCII▒ Na prática:

▒ 0x00 – 0x7F: blz! ▒ 0x80 – 0xFF: não blz

Encodings▒ Início dos diversos encodings

▒ e dos diversos problemas

Encodings▒ No Brasil, o codepage 850 era muito usado

Exemplo▒ Você, aqui no Brasil, gostaria de dar o seu olá

▒ Se você escrever:▒ Ola!

Exemplo▒ Essa sua sequência de 4 caracteres é uma informação

▒ Informação só existe na cabeça dos seres humanos

▒ Computador não conhece informação. Computador conhece dados.

Exemplo▒ Para um computador, não existe:

▒ Ola!

▒ O que existe são estes 4 bytes (ASCII):▒ 0x4F 0x6C 0x61 0x21

Exemplo▒ Blz !

▒ O l a !▒ ↑ ↑ ↑ ↑▒ 0x4F 0x6C 0x61 0x21

Exemplo▒ Qualquer computador que entenda ASCII (e todos entendem) vai conseguir processar corretamente a sua informação

Exemplo▒ E se a gente escrever...

▒ Olá!

Exemplo▒ Blz !▒ Pois:

▒ O l á !▒ ↑ ↑ ↑ ↑▒ 0x4F 0x6C 0xE1 0x21

Exemplo▒ Até você tentar ler isso num computador russo e...

Exemplo▒ Não blz ▒ Pois:

▒ O l р !▒ ↑ ↑ ↑ ↑▒ 0x4F 0x6C 0xE1 0x21

Exemplo▒ Quem foi que falou que 0xE1 corresponde ao caractere á???▒ Codepage 850 falou!

▒ Mas codepage 855 falou que 0xE1 equivale a р!

▒ Quem está certo???

Exemplo▒ Ou seja:

Exemplo▒ Não blz ▒ Pois:

▒ O l á !▒ ↑ ↑ ↑ ↑▒ 0x4F 0x6C ???? 0x21

Encodings▒ Não existe uma forma única de representar o caractere á

▒ A sequência de bytes é ambígua:▒ 0x4F 0x6C 0xE1 0x21

▒ A não ser que...

Encodings▒ ...a gente envie para o computador russo:▒ A sequência de bytes

+▒ o encoding usado (codepage 850)

▒ E reze para o computador russo saber interpretar esse encoding

Encodings▒ É óbvio que não iria dar certo o mundo inteiro se comunicando desse jeito, cada um com seu encoding específico

▒ Seria necessário uniformizar de verdade

Encodings▒ Seria necessário...

▒ Um código...▒ Um código único...▒ Um único código...▒ Um...

UNICODE!!

Unicode▒ O que é Unicode?

▒ A) Um código único▒ B) Um encoding▒ C) Uma tabela de caracteres▒ D) Uma grande gambiarra▒ E) Todas as anteriores▒ F) Todas as anteriores e + um pouco▒ G) Todas as anteriores + MUITA coisa

The Unicode 5.0 Standard

▒ 1472 páginas▒ É grande

O que é Unicode?▒ Padrão internacional▒ Complexo▒ Extenso▒ Detalhado

O que é Unicode?▒ Duas partes interessantes para nós nesse momento:▒ UCS

▒Universal Character Set

▒ Encodings▒UTF­8, UTF­16, UTF­32 (Unicode Transformation Format)

UCS▒ Tabela gigante de caracteres

▒ Cada caractere possui um código, chamado code point▒ Code point é representado por U+ e um número em hexadecimal

UCS▒ Exemplos:

▒ U+0058: X▒ U+00E3: ã▒ U+2603: ☃▒ U+10123:

UCS▒ Caracteres mais usados estão no intervalo U+0000 a U+FFFF

▒ Esse intervalo é chamado de Basic Multilingual Plane (BMP)

UCS▒ Caracteres na tabela são abstratos (são informação)

▒ Para concretizá­los, é necessário um encoding

UTF­32▒ Usa exatamente 32 bits por caractere (4 bytes)

▒ Simplesmente pega o code point e preenche com zeros à esquerda, se necessário

▒ Parece o mais complicado, mas na verdade é o mais simples dos três

UTF­32▒ Exemplos:

▒ U+0058: 0x00 0x00 0x00 0x58▒ U+00E3: 0x00 0x00 0x00 0xE3▒ U+2603: 0x00 0x00 0x26 0x03▒ U+10123: 0x00 0x01 0x01 0x23

UTF­16▒ Usa, no mínimo, 16 bits por caractere (2

bytes)

▒ Para caracteres válidos do BMP, usa exatamente 2 bytes

▒ Para caracteres fora do BMP, usa um mecanismo similar à ideia de escape, e consome 4 bytes

▒ Sendo BMP o intervalo mais comum, UTF­16 costuma usar exatamente 2 bytes por caractere

UTF­16▒ Exemplos:

▒ U+0058: 0x00 0x58▒ U+00E3: 0x00 0xE3▒ U+2603: 0x26 0x03▒ U+10123: 0xD8 0x00 0xDD 0x23

UTF­8▒ Usa, no mínimo, 8 bits (1 byte) por caractere

▒ Pode usar de 1 a 4 bytes

▒ Parece o mais simples, mas na verdade é o mais complicado

UTF­8▒ Exemplos:

▒ U+0058: 0x58▒ U+00E3: 0xC3 0xA3▒ U+2603: 0xE2 0x98 0x83▒ U+10123: 0xF0 0x90 0x84 0xA3

UTF­8▒ Compatível com ASCII entre U+0000 e U+007F

▒ A partir de U+0080, usa mais de um byte

▒ Para os caracteres da língua portuguesa, usa 1 ou 2 bytes

Adendo...▒ UTF­16 e UTF­32 possuem ainda duas variações:▒ BE – Big Endian▒ LE – Little Endian

▒ Isso tem a ver com a ordem dos bytes (no UTF­16: “1º byte, 2º byte” ou “2º byte, 1º byte”)

Adendo...▒ Mas isso é só um detalhe irrelevante nesse momento

UCS e UTF▒ O que eu preciso saber disso tudo?

▒ Apenas o seguinte:

UCS e UTF▒ Tabela de caracteres ≠ encoding

▒ Existem formas diferentes de se representar caracteres Unicode. A mais comum é usando UTF­8.

▒ UTF­8 usa número variável de bytes por caractere (em geral, 1 ou 2)

No mundo real de hoje▒ Encodings mais usados nos sistemas que rodam no Brasil:▒ UTF­8▒ LATIN­1

LATIN­1▒ Também conhecido como ISO­8859­1▒ Define 255 caracteres▒ Similar ao codepage 850▒ 1 byte por caractere (é fixo)

LATIN­1▒ Mesma ideia dos ASCIIs estendidos:▒ 0x00 a 0x7F: igual ASCII▒ 0x80 a 0xFF: outros caracteres

▒ NÃO é um encoding para Unicode▒ 1 byte nem seria suficiente

LATIN­1▒ Relação com Unicode

▒ Caracteres LATIN­1 (0x00 a 0xFF) são exatamente os mesmos que U+0000 até U+00FF

LATIN­1▒ Exemplos

CaractereCode point (Unicode)

Código em LATIN­1

X U+0058 0x58

ã U+00E3 0xE3

☃ U+2603 Não existe

U+10123 Não existe

LATIN­1 e UTF­8▒ Agora que já vimos LATIN­1 e UTF­8, voltemos à seguinte questão:

LATIN­1 e UTF­8▒ Por que “José” vira “José”???

LATIN­1 e UTF­8▒ “José” em UTF­8:

▒ J o s é▒ ↑ ↑ ↑ ↑▒ 0x4A 0x6F 0x73 0xC3 0xA9

▒ Bytes 0x4A 0x6F 0x73 0xC3 0xA9 representam “José” em UTF­8

LATIN­1 e UTF­8▒ Mas se você não avisar que está em UTF­8 e alguém tentar ler em LATIN­1:

▒ J o s à ©▒ ↑ ↑ ↑ ↑ ↑▒ 0x4A 0x6F 0x73 0xC3 0xA9

LATIN­1 e UTF­8▒ Toda vez que você envia uma sequência de bytes e não envia o encoding junto, corre o risco de ser mal­interpretado

Parte 3

Como faz pra dar certo

Informação=

dados + formade interpretá-los

No caso de caracteres...

String..

=..bytes + encoding

Como faz pra dar certo▒ A primeira coisa a se ter na cabeça é:

Não existe string sem encoding!

Como faz pra dar certo▒ A segunda coisa a se ter na cabeça é:

Não existem bytes representando caracteres sem

encoding!

Como faz pra dar certo▒ Diretrizes para se evitar problemas de encoding:

Como faz pra dar certo▒ 1) Use sequências de escape sempre que possível

▒ Para escrever “Programação”:▒ Em Java:

▒"Programa\u00e7\u00e3o"▒ Em HTML:

▒<p>Programa&ccedil;&atilde;o</p>

Como faz pra dar certo▒ 2) Trate strings como strings

▒ Strings NÃO SÃO vetores de bytes!

Como faz pra dar certo▒ 3) Trate vetores de bytes como vetores de bytes

▒ Vetores de bytes NÃO SÃO strings!

Como faz pra dar certo▒ 4) Faça conversões só quando realmente for necessário

▒ Ao fazer qualquer conversão, SEMPRE especifique o encoding

▒ Quando é que realmente precisamos fazer conversões?▒ Quando fazemos entrada/saída

Como faz pra dar certo▒ Exemplos:

Como faz pra dar certo▒ Você tem uma string na mão e quer procurar ocorrências de uma letra acentuada nela?

▒ Então nesse caso você NÃO PRECISA mexer com encoding!

▒ Repare que não existe operação de entrada/saída nesse caso

▒ Você deve apenas escapar o caractere desejado, por segurança

Como faz pra dar certo

public int buscarAAcentuado(String str) {

return str.indexOf('\u00e1');

}

Como faz pra dar certo▒ Você vai enviar texto em uma requisição HTTP?▒ Converta a string para bytes usando algum encoding

▒ Avise ao servidor que você vai usar esse encoding

▒ Envie os bytes

Como faz pra dar certo▒ Certo:

▒ Content­Type: text/plain; charset=utf­8

▒ Content­Type: text/plain; charset=iso­8859­1

▒ Errado:▒ Content­Type: text/plain (não existe texto sem encoding!)

Como faz pra dar certo▒ Recomendado:

▒ UTF­8▒<form accept­charset="utf­8">▒Content­Type: application/x­www­form­urlencoded; charset=utf­8

▒ LATIN­1▒<form accept­charset="iso­8859­1">▒Content­Type: application/x­www­form­urlencoded; charset= iso­8859­1

Como faz pra dar certo▒ Você vai fazer um proxy (baixar conteúdo e enviá­lo para algum outro lugar)?▒ Baixe o conteúdo (bytes)▒ Leia qual é o encoding do conteúdo▒ Repasse o encoding ▒ Repasse os bytes▒ Não mexa no conteúdo nem no encoding

Como faz pra dar certo▒ Vai baixar um JSON da internet?

▒ Caso fácil▒ Caso bizarro

Como faz pra dar certo▒ JSON – caso fácil (codificado em UTF­8, UTF­16 ou UTF­32)▒ Baixe o conteúdo (bytes)▒ Repasse os bytes para a sua biblioteca de processamento de JSON

▒ Padrão JSON define um mecanismo de detecção automática de qual encoding UTF foi usado▒Geralmente vai estar em UTF­8

Como faz pra dar certo▒ JSON – caso bizarro (codificado em LATIN­1)▒ ???▒ Isso foge da especificação!

▒Fazer o quê... Acontece!▒ Processe­o em LATIN­1 mesmo...

Como faz pra dar certo▒ Vai baixar um XML da internet?

▒ Baixe o conteúdo (bytes)▒ Repasse os bytes para a sua biblioteca de processamento de XML

▒ XML informa seu encoding dentro do próprio documento

Como faz pra dar certo▒ Vai escrever um JSON seu para o cliente?

▒ Converta o JSON em string▒ Converta a string em bytes usando UTF­8▒ Defina encoding de saída como sendo UTF­8▒ Escreva os bytes para o cliente▒ Especificar charset de JSON não deveria ser necessário, mas algumas implementações exigem. Portanto, o melhor é fazer:▒ Content­Type: application/json;charset=utf­8

Como faz pra dar certo▒ “Você fica dizendo aí toda hora que tem passar o encoding, tem que passar encoding... E se eu não passar o encoding? Não funciona?”

Como faz pra dar certo▒ Funciona!

▒ ...às vezes!

▒ O que acontece se eu não especificar encoding?▒ Nenhum encoding será usado!▒ Certo!?

!!!!!!!!!!!

!!ERRADO!!

!!!!!!!!!!!

Como faz pra dar certo▒ Se você não especificar encoding, será usado o encoding padrão da plataforma

▒ E isso é ERRADO!▒ É um perigo!▒ É um absurdo!

Como faz pra dar certo▒ Plataformas MUDAM!▒ Configurações de ambiente MUDAM!▒ Encoding padrão MUDA!

Dica em Java▒ byte[] meusBytes =

string.getBytes("UTF­8");

▒ String minhaString =new String(bytes, "UTF­8");

Dica em Java▒ Chamando sempre esses métodos e passando o encoding correto, você nunca gerará problemas de encoding no seu código

▒ Apesar disso, nada impede de o problema estar fora do seu código

▒ De qualquer forma, faça sua parte

Conclusões▒ Problemas de encoding acontecem nas melhores famílias

Conclusões▒ Qualquer peça do quebra­cabeça pode estragar tudo

▒ Programação defensiva costuma ser a melhor (e talvez a única) solução

Conclusões▒ Causas são sempre as mesmas:

▒ String sendo lida e/ou escrita usando o encoding errado

▒ Uso indevido do encoding padrão da plataforma

▒ Causa raiz de todo o problema:▒ Ambiguidade: mais de uma maneira de representar a mesma informação

Conclusões▒ Apenas reforçando:

▒ Não existe informação sem forma de interpretação

▒ Não existe string sem encoding

Referências▒ The Unicode Consortium

▒ http://unicode.org/

▒ The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)▒ http://www.joelonsoftware.com/articles/Unicode.html

Referências▒ Lista de caracteres Unicode e suas diferentes representações▒ http://www.fileformat.info/info/unicode/

Referências▒ ASCII

▒ http://en.wikipedia.org/wiki/ASCII

▒ Unicode▒ http://en.wikipedia.org/wiki/Unicode

▒ UTF­8▒ http://en.wikipedia.org/wiki/UTF­8