Minicurso de Encoding
André Willik Valenti (Daitan)Andrei Tognolo (Dextra)
The Developer’s Conference 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
Encoding? Hein!?▒ 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題 uAssun 褯 Jr
Por que 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!
Por que encoding?▒ Veja esta imagem
Por que encoding?▒ Esta imagem é uma informação
▒ Como a gente representa essa informação no computador?
Por que encoding?▒ Formato da imagem é JPEG
▒ Mas o que é uma imagem JPEG?
▒ Podemos olhar para “uma imagem JPEG” sob quais pontos de vista?
Uma imagem mesmo?
Um monte de pixels?
Um monte de bytes?
Um grande número binário?
1111111111011000111111111110000000000000000100000100101001000110100100101000110000000000000000100000001000000010000000001011111
...
Por que encoding?▒ A resposta correta é:
▒ Todas são diferentes formas de enxergar a mesma coisa
Por que encoding?▒ 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
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▒ Exemplos:
ASCII Decimal Hexa Binário
5 53 0x35 0110101
A 65 0x41 1000001
} 125 0x7D 1111101
ASCII▒ Intervalo válido
▒ Em decimal: 0 – 127▒ Em binário: 0000000 – 1111111▒ Em hexadecimal: 0x00 – 0x7F
ASCII▒ Somente 128 caracteres...
▒ Nenhum caractere acentuado
ASCII▒ Em vez de usar apenas 7 bits, muitas máquinas usavam/usam 8
▒ E esse bit sobrando aí?▒ Já sei!!!▒ Vamos usar pra codificar caracteres locais de cada país!
ASCII▒ Com 8 bits, conseguimos representar 256 diferentes caracteres
▒ Intervalo válido:▒ 0 – 255 (em decimal)▒ 0x00 – 0xFF (em hexadecimal)
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
ASCII▒ E por que de 0x80 a 0xFF é “não blz”?
▒ Já vamos ver por quê...
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 (hexa)▒ 79 108 97 33 (decimal)
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
Encodings▒ Mas e se...▒ ...a gente enviar para o computador russo o seguinte:▒ A sequência de bytes
+▒ O encoding usado (codepage 850)
▒ Será que dá certo?▒ Segure essa ideia!
ISO-8859-1▒ Também conhecido como LATIN-1▒ Mesma ideia dos ASCII estendidos:▒ 255 caracteres▒ Compatível com ASCII
Encodings▒ É óbvio que não iria dar certo o mundo inteiro tentando se comunicar cada um usando 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?
The Unicode 5.0 Standard
▒ 1472 páginas▒ É grande
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 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 um 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
▒ 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▒ Serve para caracteres Unicode?
LATIN-1▒ NÃO é um encoding para Unicode
▒ Usa exatamente 1 byte por caractere▒ 1 byte não seria suficiente
▒ Mesma ideia dos ASCIIs estendidos:▒ 0x00 a 0x7F: igual ASCII▒ 0x80 a 0xFF: outros caracteres
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▒ 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▒ E se você enviar 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▒ Se você não avisar que o seu texto está em UTF-8, como a pessoa vai adivinhar?
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
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
▒ 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▒ 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▒ Vai receber um XML?
▒ Receba 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▒ “Tem que 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!
Java: jeito errado▒ byte[] meusBytes =
string.getBytes();
▒ String minhaString =new String(bytes);
Java: jeito certo▒ byte[] meusBytes =
string.getBytes("UTF-8");
▒ String minhaString =new String(bytes, "UTF-8");
Demonstração...
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
Contatos▒ André Willik Valenti
▒ [email protected]▒ @awvFi
▒ Andrei de Oliveira Tognolo▒ [email protected]▒ /andreitognolo