Minicurso de Encoding - resolvendo problemas com acentuação (#TDC2012 Goiânia)

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ça!

Citation preview

Minicurso de Encoding

André Willik Valenti (Daitan Group)Andrei Tognolo (Dextra Sistemas)

The Developer’s ConferenceGoiânia 2012

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

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題 uAssun 褯 Jr

Quem é o encoding?▒ Mais especificamente:

▒ Character encoding

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

Por que encoding?▒ Se dá tanto problema...

▒ Por que a gente usa?

Por que encoding?▒ Computador é uma máquina de armazenar e processar informação

▒ Informação é um conceito abstrato

▒ Computador não entende conceitos abstratos

▒ Computador entende de bits, bytes, números

Por que encoding?▒ Exemplo: imagens

Por que encoding?▒ Como a gente representa uma imagem num computador?▒ Imagem pixels▒ pixels números▒ números bytes/bits▒ bytes/bits algum formato

(png, jpeg, gif etc.)

PNG

100011000100100100...

(440KB)

00110001011...

(62KB)

JPEG

Por que encoding?▒ A imagem é uma informação

▒ Bytes / bits são dados

▒ Dados são concretos, informação é abstrata

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

Informação=

dados + formade interpretá-los

Encoding▒ “Forma de interpretá-los”

▒ Isso é o encoding!

Encoding▒ Exemplos de encoding:

▒ PNG▒ JPEG▒ MPEG▒ MP3▒ PDF

Character encoding▒ O que é então um character encoding?▒ É só uma determinada maneira de se representar caracteres usando bytes

Encoding▒ Por que a gente usa encoding, então?▒ Porque não tem como não usar!

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

▒ Bob Bemer:▒ “Vamos uniformizar esse negócio...”

ASCII▒ American Standard Code for Information Interchange

▒ 7 bits

▒ 128 diferentes caracteres

ASCII▒ ASCII é, ao mesmo tempo:

▒ Um encoding▒ Uma tabela de caracteres

ASCII▒ Exemplos:

Caractere Decimal Hexa Binário

5 53 0x35 0110101

A 65 0x41 1000001

} 125 0x7D 1111101

ASCII▒ 128 caracteres (nenhum acentuado)

▒ Intervalo válido▒ Em decimal: 0 – 127▒ Em binário: 0000000 – 1111111▒ Em hexadecimal: 0x00 – 0x7F

ASCII▒ 7 bits?

▒ Muitas máquinas usavam/usam o padrão de 8 bits para 1 byte

▒ E esse bit sobrando aí?▒ “Já sei... Vamos usar pra codificar caracteres locais de cada país!”

ASCII estendido▒ 8 bits: 256 caracteres

▒ Intervalo válido:▒ 0 – 255 (em decimal)▒ 0x00 – 0xFF (em hexadecimal)

ASCII estendido▒ 0x00 – 0x7F: igual ASCII

▒ a b C D 3 5 9 % & /

▒ 0x80 – 0xFF: caracteres locais▒ ç Á ã é ü ¿

0x80 0x81 0x82 ... 0xFF

ASCII original

ASCII estendido

0x00 0x01 0x02 ... 0x7F

ASCII estendido▒ Problema:

▒ Não existe “o encoding ASCII estendido”

▒ Existem UM MONTE de encodings que são “ASCII estendido”

ASCIIs estendidos▒ Codepages

▒ 437 — The original IBM PC code page▒ 720 — Arabic▒ 737 — Greek▒ 775 — Estonian, Lithuanian and Latvian▒ 850 — "Multilingual (Latin-1)"▒ 852 — "Slavic (Latin-2)"▒ 855 — Cyrillic▒ 857 — Turkish▒ 858 — "Multilingual" with euro symbol▒ 860 — Portuguese▒ 863 — French (Quebec French) ▒ 865 — Danish/Norwegian▒ 866 — Cyrillic ▒ 869 — Greek ▒ 874 — Thai▒ ...

ASCIIs estendidos▒ ISO-8859-1

▒ Também conhecido como LATIN-1

▒ É um ASCII estendido:▒ 256 caracteres▒ Compatível com ASCII

▒ Usado até hoje

ASCIIs estendidos▒ Maravilha!

▒ Milhares de encodings diferentes

▒ Agora todo mundo vai conseguir representar seus caracteres!

ASCIIs estendidos▒ E a interoperabilidade?

▒ Internet, internacionalização?▒ Troca de textos, documentos?▒ Nomes de arquivos?

Júnior.txt

Olá, meu nome é José Luàs de

Assunção Júnior, sou irmão da SÃ

lvia, da Cláudia e do João.

ASCII▒ No fim das contas, ficou assim:

ASCII▒ Na teoria:

▒ ASCII original: 0x00 – 0x7F

▒ Extensão do ASCII: 0x80 – 0xFF

ASCII▒ Na prática:

▒ ASCII original: Blz!

▒ Extensão do ASCII: Esquece!

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

▒ Você escreve:▒ Ola!

▒ No Brasil, a gente usava o encoding chamado “Codepage 850” (ou CP850)

Exemplo▒ Essa sua sequência de 4 caracteres (“Ola!”) é 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:▒ 0x4F 0x6C 0x61 0x21

▒ Resultado:

Exemplo▒ Blz !

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

Exemplo▒ Mensagem foi codificada em CP850

▒ Todos os caracteres eram ASCII também

▒ Na prática:▒ A mensagem está em ASCII▒ Todo computador entende ASCII▒ Então blz!

Exemplo▒ E se a gente escrever...

▒ Olá!

▒ Resultado:

Exemplo▒ Blz !

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

▒ (Usando codepage 850)

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

Exemplo▒ Não blz

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

Exemplo▒ Encoding russo disse:

▒ 0xE1 é um р

▒ Encoding brasileiro tinha dito:▒ 0xE1 é um á

▒ Quem está certo?

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

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

Encodings▒ E se tivesse um jeito...

▒ ...de informar ao computador russo que a gente usou o CP850?

▒ Segure essa ideia!

Encodings▒ O mundo inteiro...

▒ ...cada um com o seu encoding?

▒ É óbvio que não daria certo▒ Teria que uniformizar de verdade!

Encodings▒ E se houvesse...

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

UNICODE!!

Unicode▒ O que é Unicode?

The Unicode 5.0 Standard

▒ 1472 páginas▒ É grande

O que é Unicode?▒ Unicode é:

▒ Um padrão gigantesco▒ Subdividido em muitas partes

▒ Unicode, ao contrário do ASCII:▒ Não É uma tabela de caracteres▒ Não É um encoding

O que é Unicode?▒ Unicode TEM uma tabela de caracteres:▒ UCS: Universal Character Set

▒ Unicode TEM diversos encodings▒ UTF-8, UTF-16, UTF-32 (Unicode Transformation Format)

UCS▒ Tabela gigante de caracteres (~100.000)

▒ 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▒ Intervalo U+0000 – U+007F

▒ Mesmos caracteres da tabela ASCII

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

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

Encodings Unicode▒ Maneiras de transformar caracteres abstratos em concretos

▒ Três principais: UTF-8, UTF-16, UTF-32

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▒ Exemplos:

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

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 1 byte

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

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

▒ Apenas o seguinte:

UCS e UTF▒ Tabela de caracteres ≠ encoding

▒ Diferentes de representação▒ Mais comum: UTF-8

▒ UTF-8▒ 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

No mundo real de hoje▒ U+0000 – U+007F

▒ Mesmos caracteres da tabela ASCII

▒ U+0000 – U+00FF▒ Mesmos caracteres da tabela LATIN-1

LATIN-1▒ Serve para representar qualquer caractere Unicode?

LATIN-1▒ Não!

▒ Usa exatamente 1 byte por caractere▒ 1 byte não seria suficiente

LATIN-1 e UTF-8▒ Exemplos

CaractereBytes usando

UTF-8Bytes usando

LATIN-1

X 0x58 0x58

à 0xC3 0xA3 0xE3

☃ 0xE2 0x98 0x83 Não existe

LATIN-1 e UTF-8▒ Blz!

▒ Então vamos representar a string “José”

▒ String: é uma informação ou um dado?

LATIN-1 e UTF-8▒ Lembra o Barakis Obamis com o PNG e o JPEG?

PNG

100011000100100100...

(440KB)

00110001011...

(62KB)

JPEG

LATIN-1 e UTF-8▒ O José com o LATIN-1 e UTF-8 é a mesma coisa!

LATIN-1

0x4A 0x6F 0x73 0xE9

(4 bytes)

UTF-8

José

0x4A 0x6F 0x73 0xC3 0xA9

(5 bytes)

LATIN-1 e UTF-8▒ Blz. Mas por que eu escrevo “José” num lugar e depois aparece “José” no outro?

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

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

LATIN-1 e UTF-8▒ Aí você envia esses bytes

0x4A 0x6F 0x73 0xC3 0xA9

para alguém

LATIN-1 e UTF-8▒ Se a pessoa ler em UTF-8, blz!

▒ 0x4A 0x6F 0x73 0xC3 0xA9

↓ ↓ ↓ ↓ J o s é

LATIN-1 e UTF-8▒ Mas e se ela ler em LATIN-1?

▒ 0x4A 0x6F 0x73 0xC3 0xA9

↓ ↓ ↓ ↓ ↓ J o s à ©

LATIN-1 e UTF-8▒ O texto foi:

▒ Escrito em UTF-8▒ Enviado a outro sistema

▒ Como o outro sistema vai adivinhar que o texto está em UTF-8?

Unicode▒ Mas então não é só todo mundo codificar seus caracteres usando Unicode e vai dar tudo certo!?

Unicode▒ Calma ...

▒ Em 1º lugar, Unicode não é um encoding. Não existe “codificar caracteres usando Unicode”.

▒ Em 2º lugar, não temos controle sobre todos os sistemas do mundo. Não podemos fazer com que todos usem o mesmo encoding (nem deveríamos).

Parte 3

Como faz pra dar certo

Informação=

dados + formade interpretá-los

Informação String

= =

Dados Bytes

+ +

Forma de interpretá-los

Encoding

String..

=..bytes + encoding

Não existe string sem encoding!

Não existe relação byte caractere sem encoding!

Como faz pra dar certo▒ 2 dicas para 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) Faça conversões só quando realmente for necessário

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

Como faz pra dar certo▒ Vetor de bytes não é string!▒ String não é vetor de bytes!

▒ O que é válido é:▒ Decompor string em vetor de bytes + encoding

▒ Compor string a partir de um vetor de bytes + um encoding

Como faz pra dar certo▒ Quando é que realmente precisamos fazer conversões?▒ Quando fazemos entrada/saída

Como faz pra dar certo▒ Exemplos:

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▒ Errado:

▒ Content-Type: text/plain

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

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

Como faz pra dar certo▒ Vai receber um XML?

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

Como faz pra dar certo▒ Não preciso me preocupar com encoding ao processar XML?▒ Em geral, não!▒ XML informa seu encoding dentro do próprio documento▒ <?xml version="1.0" encoding="utf-8"?>▒ (deveria, pelo menos!)

Como faz pra dar certo▒ “Tem que passar o encoding, tem que passar o 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!

Java: jeito errado▒ byte[] meusBytes =

string.getBytes();

(...)

String minhaString =new String(bytes);

▒ Está dependente de plataforma!

Java: jeito certo▒ byte[] meusBytes =

string.getBytes("UTF-8");

(...)

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

▒ Agora, sim, independe de plataforma!

Java: jeito certo▒ Não precisa ser UTF-8, pode ser qualquer outro

Java: jeito certo▒ byte[] meusBytes =

string.getBytes("LATIN1");

(...)

String minhaString =new String(bytes,

"LATIN1");

Java: jeito certo▒ byte[] meusBytes =

string.getBytes("UTF-16");

(...)

String minhaString =new String(bytes, "UTF-

16");

Java: jeito certo▒ byte[] meusBytes =

string.getBytes("UTF-32");

(...)

String minhaString =new String(bytes, "UTF-

32");

Demonstração...

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

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▒ A solução é:

▒ Lembrar: não existe string sem encoding!

▒ Informar o encoding toda vez que fizer entrada/saída

Referências▒ 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/

▒ The Unicode Consortium▒ http://unicode.org/

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

Adendo▒ “José” em UTF-8 gasta 8 bytes?

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

▒ Encoding padrão da plataforma?▒ Em geral, é errado usar▒ Em raras situações, é correto. Ex: upload de arquivo no cliente.

Contatos▒ Andr\u00e9 Willik Valenti

▒ awvalenti@gmail.com▒ @awvFi

▒ Andrei de Oliveira Tognolo▒ andreitognolo@gmail.com▒ /andreitognolo