Converter iso-8859-1 para utf-8

1,010 views
Skip to first unread message

Gustavo Henrique

unread,
Jun 30, 2009, 2:01:46 PM6/30/09
to Django Brasil
Sei que alguns já devem estar de saco cheio sobre esse assunto, mas
estou com um problema que nao consegui resolver.
Meu site está todo codificado para utf-8, até mesmo o banco de dados.
Estou fazendo uma integração com o serviço pagamentodigital.com.br e
tal porcaria é incapaz de proporcionar uma opção ao usuário sobre qual
codificacao usar, enviando apenas em iso-8859-1.
Utilizando o normalize, consegui retirar todos os caracteres
acentuados e entao salvar os dados no BD. O problema é que dentro da
mesma view eu preciso enviar um POST contendo algumas váriaveis no
formato original (iso-8859-1) e esse é o problema. A string no caso
contém a palavra Transação. Todas as minhas conversões resultaram em
Transacao, Transa, Transa???, Transao,... tudo menos Transação.

Alguém sabe como posso reconverter para iso-8859-1? Não consigo
converter Transação em iso-8859-1.

Um abraço!

Ademilson Ferreira

unread,
Jun 30, 2009, 2:27:26 PM6/30/09
to django...@googlegroups.com
2009/6/30 Gustavo Henrique <gusta...@gmail.com>:

A manha é decodificar pra unicode e codificar para outra codificação.

u'Transação'.encode('iso-8859-1')

Segue abaixo o link para uma apresentação sobre unicode no python,
espero que ajude.

http://farmdev.com/talks/unicode/

Ademilson Ferreira

Gustavo Henrique

unread,
Jun 30, 2009, 3:06:57 PM6/30/09
to django...@googlegroups.com
A manha é decodificar pra unicode e codificar para outra codificação.

u'Transação'.encode('iso-8859-1')

Essa dica acima só exibe corretamente se usar o print antes. Por que isso?

Tentei

        POST = []
        for k in request.POST.keys():
            #POST.append((k, normalize('NFKD', request.POST.get(k)).encode('ASCII','ignore')))
            v = repr(u'%s' % request.POST.get(k))
            POST.append((k, v.encode('iso-8859-1','ignore')))
        P = dict(POST)
        return HttpResponse(u'%s' % P['status']) # retorna u'Transa\ufffd'

 

Segue abaixo o link para uma apresentação sobre unicode no python,
espero que ajude.

http://farmdev.com/talks/unicode/




--
Gustavo Henrique
Site: http://www.gustavohenrique.net
Blog: http://blog.gustavohenrique.net

Luciano Rodrigues da Silva

unread,
Jun 30, 2009, 3:08:23 PM6/30/09
to django...@googlegroups.com
http://www.python.org.br/wiki/TudoSobrePythoneUnicode

Esse texto deveria ser de leitura obrigatória. Depois dele duvido que
vc ainda tenha duvidas sobre Python e Unicode.

--
Até,

Luciano

<quote>
"Na prática, a teoria é outra!"
</quote>

:wq!

Nycholas de Oliveira e Oliveira

unread,
Jun 30, 2009, 4:03:39 PM6/30/09
to django...@googlegroups.com
^^,

> Essa dica acima só exibe corretamente se usar o print antes. Por que isso?

Defina explicitamente no seu `HttpResponse` a tabela de codificação,

st = u'Transação'.encode('iso-8859-1')
return HttpResponse(st, content_type='text/plain; charset=iso-8859-1')

> return HttpResponse(u'%s' % P['status']) # retorna u'Transa\ufffd'

Note que você esta retornando um objeto unicode.

Se isso é esperado, então defina o `charset` do `HttpResponse` como utf-8,

st = u'Transação'
return HttpResponse(st, content_type='text/plain; charset=utf-8')


--
Até mais e boa sorte,
Nycholas de Oliveira e Oliveira.

Gustavo Henrique

unread,
Jun 30, 2009, 4:31:30 PM6/30/09
to django...@googlegroups.com
Nycholas, seu exemplo funcionou, mas no meu caso ainda nao esta dando certo.

A string correta é "Transação em Andamento"

return HttpResponse(repr(request.POST.get('status')))
u'Transa\ufffd em Andamento'

return HttpResponse(request.POST.get('status').encode('ascii','replace'),content_type='text/plain;
charset=iso-8859-1')
Transa? em Andamento

return HttpResponse(request.POST.get('status').encode('utf-8'),content_type='text/plain;
charset=utf-8')
Transa� em Andamento

u = u'Transa\ufffd em Andamento'
print u
Transa� em Andamento

print u.encode('utf-8')
Transa� em Andamento

print u.encode('iso-8859-1','ignore')
Transa em Andamento

Todas as combinacoes que eu tento nao retornam Transação.

Luciano Ramalho

unread,
Jun 30, 2009, 6:41:58 PM6/30/09
to django...@googlegroups.com
2009/6/30 Gustavo Henrique <gusta...@gmail.com>:

> Essa dica acima só exibe corretamente se usar o print antes. Por que isso?

Gustavo, a questão do print não está relacionada a problemas de
encoding, e sim de uma característica do console do Python. Veja
atentamente estes exemplos:

>>> c = 'casa'
>>> c
'casa'
>>> print c
casa
>>> print repr(c)
'casa'

Veja a diferença: o que acontece é que quando o console interativo
mostra um valor, ele usa a função repr() que serve para mostrar
valores de uma forma sem ambiguidades para programadores, por isso uma
string aparece entre aspas. Quando se usa o print por default é usada
a função str() para gerar a saída, e esta função tenta mostrar o
objeto de uma forma mais "amigável", mas não tão precisa. Veja este
outro exemplo:

>>> u = u'bola'
>>> u
u'bola'
>>> print u
bola
>>>

Note que a representação (repr) de uma string unicode tem, além das
aspas, um prefixo u, mas nada disso aparece quando se dá print.

Quando existem caracteres não-ASCII, a diferença é ainda mais gritante:

>>> b = 'maçã'
>>> b
'ma\xc3\xa7\xc3\xa3'
>>> print b
maçã
>>> print repr(b)
'ma\xc3\xa7\xc3\xa3'
>>>

A função repr() exibe qualquer caractere não-ASCII como um código
hexadecimal. Isso não é um erro, é o Python sendo preciso, porque
dependendo do encoding do terminal o mesmo código hexadecimal pode
representar um caractere diferente.

A maior precisão do repr() fica evidente também quando se lida com
números, veja:

>>> a = 1.1
>>> a
1.1000000000000001
>>> print a
1.1
>>> print repr(a)
1.1000000000000001
>>> print str(a)
1.1
>>>

Como assim, Python acha que 1.1 é o mesmo que 1.1000000000000001????????

Sim, e a culpa não é do Python, e sim das imprecisões inerentes à
representação de números reais em computadores. Essa mesma imprecisão
existe na linguagem C, que é a base de Python e da maioria das
linguagens modernas. Note que embora visualmente chocante, este erro é
bem pequeno, acontece na 16a casa decimal. Mesmo assim, ao usar
automaticamente a função str, o comando print "esconde" esta
imprecisão, mas ela está lá.

É por isso que não se deve comparar números de ponto flutuante com a
== b, deve-se sempre fazer uma aproximação comparando a diferença, do
tipo:

if abs(a-b) < epsilon: ...

Onde epsilon é um nome tradicional para um valor pequeno que
representa a precisão com a qual você quer trabalhar.

[ ]s
Luciano

Gustavo Henrique

unread,
Jul 1, 2009, 11:03:57 AM7/1/09
to django...@googlegroups.com
Obrigado pela "aula", Luciano!

O robo do pagamentodigital me envia uma requisicao no formato iso-8859-1.
Os valores da variavel request já estão em formato unicode, certo?
Porque ao imprimir dentro de um arquivo texto o conteudo do request,
obtenho:

u'status': u'Transa\ufffd em Andamento'

definindo um encoding padrao (sys.setdefaultencoding()) como utf-8,
latin-1, ascii ou iso-8859-1, o resultado é o mesmo como acima.

no shell do python:

s = u'Transa\ufffd'
e = s.encode('utf-8') #'Transa\xef\xbf\xbd'
print e # Transa�

e = s.encode('iso-8859-1','replace') # 'Transa?'

Não consigo transformar a string novamente para Transação.

Luciano Ramalho

unread,
Jul 1, 2009, 11:10:28 AM7/1/09
to django...@googlegroups.com
2009/7/1 Gustavo Henrique <gusta...@gmail.com>:

>
> Obrigado pela "aula", Luciano!
>
> O robo do pagamentodigital me envia uma requisicao no formato iso-8859-1.
> Os valores da variavel request já estão em formato unicode, certo?
> Porque ao imprimir dentro de um arquivo texto o conteudo do request,
> obtenho:
>
> u'status': u'Transa\ufffd em Andamento'

\ufffd é um código Unicode especial que significa "caractere
indefinido". Ou seja, esta string já está corrompida de cara, nada
mais que você possa fazer vai consertá-la.

Portanto o problema está acontecendo antes deste ponto, provavelmente
na conversão dos dados recebidos para unicode.

[ ]s
Luciano

Gustavo Henrique

unread,
Jul 1, 2009, 11:17:32 AM7/1/09
to django...@googlegroups.com
Hum... então está explicado.

Será que o método do django responsável por converter os valores do
request para unicode está causando esse problema?
Se sim, há alguma forma de contornar isso?

Luciano Ramalho

unread,
Jul 1, 2009, 11:35:11 AM7/1/09
to django...@googlegroups.com
2009/7/1 Gustavo Henrique <gusta...@gmail.com>:

>
> Hum... então está explicado.
>
> Será que o método do django responsável por converter os valores do
> request para unicode está causando esse problema?
> Se sim, há alguma forma de contornar isso?

Eu acho mais provável que a falha esteja na requisição enviada pelo
robô do que no Django ou no Python. Por exemplo, o robô pode estar
declarando um determinado encoding no cabeçalho da requisição e usando
outro encoding no corpo. Esse erro é muito comum.

[ ]s
Luciano

Thiago Paiva ::

unread,
Jul 1, 2009, 5:43:36 PM7/1/09
to Django Brasil
Cara,

Eu passei por aguns problemas semelhantes quando trabalhava com "web
crawlers", mas no seu caso o problema é mais simples já que vc sabe
qual codificação recebe e qual a codificação que deseja...
Seguinte: Transforma tua entrada em string e chama 'string.decode
(encoding)'. Esse método pega tua string e transforma pra a
codificação padrão do Python que (se vc não mudou nada) é 'ascii'. Daí
vc pode pegar essa string e chamar 'string.encode(novoencoding)' pra
mandar ela pra a codificação que vc deseja.
Agora tem um porém: quando eu trabalhei com isso, dava muito pau pois
tem alguns caracteres UTF-8 e ISO que não são convertidos pra ASCII
pelo interpretador corretamente, então eu solucionei mudando a
codificação padrão do interpretador pra UTF-8 em '(PYTHONROOT)/Lib/
site.py'.
Tenta ai e vê o que vc consegue...

Hasta!

Luciano Ramalho

unread,
Jul 1, 2009, 8:09:39 PM7/1/09
to django...@googlegroups.com
2009/7/1 Thiago Paiva :: <tpbo...@gmail.com>:

>
> Cara,
>
> Eu passei por aguns problemas semelhantes quando trabalhava com "web
> crawlers", mas no seu caso o problema é mais simples já que vc sabe
> qual codificação recebe e qual a codificação que deseja...
> Seguinte: Transforma tua entrada em string e chama 'string.decode
> (encoding)'. Esse método pega tua string e transforma pra a
> codificação padrão do Python que (se vc não mudou nada) é 'ascii'.

Isso não resolve o problema com acentos.

> Daí
> vc pode pegar essa string e chamar 'string.encode(novoencoding)' pra
> mandar ela pra a codificação que vc deseja.
> Agora tem um porém: quando eu trabalhei com isso, dava muito pau pois
> tem alguns caracteres UTF-8 e ISO que não são convertidos pra ASCII
> pelo interpretador corretamente,

Claro que não, porque simplesmente a tabela ASCII não contem nenhum
caractere acentuado, portanto é *impossível* converter tais caracteres
para ASCII, por definição.

Veja só:

http://pt.wikipedia.org/wiki/Ascii

> então eu solucionei mudando a
> codificação padrão do interpretador pra UTF-8 em '(PYTHONROOT)/Lib/
> site.py'.
> Tenta ai e vê o que vc consegue...

Fazendo isso a codificação padrão do Python deixa de ser ASCII, e
passa a ser UTF-8. É uma possível solução, mas também pode ser dar um
tiro de canhão para matar uma mosca.

[ ]s
Luciano

Gustavo Henrique

unread,
Jul 1, 2009, 9:23:48 PM7/1/09
to django...@googlegroups.com
O problema são os tais caracteres que não podem ser convertidos para ASCII.
Estou trabalhando sobre a hipótese do que o Luciano disse, que a url
está chegando mal formada. Entrei em contato com o suporte, digo,
atendimento, do pagamentodigital e estou aguardando resposta.
Apesar de tudo, o que me deixa mais indignado é o fato de uma empresa
que presta esse tipo de serviço não fornecer uma alternativa de
encoding. Uma opção simples que a maioria das empresas que fornecem
webservice dispõem.

Um abraço!

Reply all
Reply to author
Forward
0 new messages