Upload
andre-willik-valenti
View
6.621
Download
1
Embed Size (px)
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çã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
▒ [email protected]▒ @awvFi
▒ Andrei de Oliveira Tognolo▒ [email protected]▒ /andreitognolo