Minicurso de Encoding André Willik Valenti (Daitan) Andrei Tognolo (Dextra) The Developer’s Conference 2012
May 26, 2015
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