Como pegar o texto de um Entry() e Text() como unicode no Tkinter?

769 views
Skip to first unread message

Mário Neto

unread,
Dec 14, 2012, 9:57:28 AM12/14/12
to python...@googlegroups.com
Erro ao tentar salvar a palavra Mário em um campo do tipo Entry()

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)

--
Att. Mário Araújo Chaves Neto
Programmer, Designer and U.I. Engineer

MBA in Design Digital - 2008 - FIC
Analysis and Systems Development - 2011 - Estácio
Design and Implementation of Internet Environments - 2003 - FIC

Maxwell Morais

unread,
Dec 14, 2012, 10:01:45 AM12/14/12
to python...@googlegroups.com
Mário, você está utilizando str()  em algum ponto da função. ex:

nome = str(self.entry_nome.get())

por que eu utilizo Tkinter também, e isto não me ocorre, caso você esteja fazendo isto, troque str por unicode, ou coloque o trecho do seu código para que possamos te ajudar.


2012/12/14 Mário Neto <macnd...@gmail.com>

--
--
------------------------------------
Grupo Python-Brasil
http://www.python.org.br/wiki/AntesDePerguntar
 
<*> Para visitar o site do grupo na web, acesse:
http://groups.google.com/group/python-brasil
 
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@googlegroups.com
 
 
 



--


Maxwell Morais
(+55 11) 3774-1137
 www.realizemodulados.com.br

Mário Neto

unread,
Dec 14, 2012, 11:12:07 AM12/14/12
to python...@googlegroups.com
Opa Maxwell, estou usando Windows e Python 2.7 e não estou utilizando nem str() e nem unicode()
Código completo do meu estudo de tkinter:

Maxwell Morais

unread,
Dec 14, 2012, 11:15:08 AM12/14/12
to python...@googlegroups.com
Uma pergunta o erro corre na função salvar dados correto?

Luciano Ramalho

unread,
Dec 14, 2012, 11:16:23 AM12/14/12
to python...@googlegroups.com
O Mário, não tenho tempo de ler seu código agora, mas o Maxwell deve ter dado a dica certa: a questão é que mesmo que você não use a função str, se em algum lugar estiver misturando unicode com str estará acontencendo uma conversão automática de str para unicode, e nesse caso o Python assume que o conteúdo do str deve ser ASCII puro. Para lidar com segurança com texto acentuado em Python você deve sempre converter explicitamente qualquer dado de entrada de str para unicode e fazer a operação inversa ao salvar em arquivo.

[ ]s
Luciano

2012/12/14 Mário Neto <macnd...@gmail.com>



--
Luciano Ramalho / OFICINAS TURING
Twitter: @ramalhoorg

Autor e professor dos cursos:

* Objetos Pythonicos   -->   http://turing.com.br/oopy
* Python para quem sabe Python   -->   http://turing.com.br/ppqsp

Maxwell Morais

unread,
Dec 14, 2012, 11:19:07 AM12/14/12
to python...@googlegroups.com
O Luciano está correto.

Você está tentando realizando o seguinte:


with open('dados.txt', 'a') as dados:
dados.write('Nome: %s\n' % nome.get())
dados.write('Categoria: %s\n' % categoria.get())
dados.write('Endereco:\n%s\n' % endereco.get('1.0', END))

por padrão o python entende que '' ou '' são strings do tipo str
a notação é u'' ou u"" então tente:

with open('dados.txt', 'a') as dados:
dados.write(u'Nome: %s\n' % nome.get())
dados.write(u'Categoria: %s\n' % categoria.get())
dados.write(u'Endereco:\n%s\n' % endereco.get('1.0', END))

Com isto você não terá problema algum.

Mário Neto

unread,
Dec 14, 2012, 11:40:54 AM12/14/12
to python...@googlegroups.com
Valeu Luciano e Maxwell!
Mesmo dessa forma (convertendo pra unicode através do u'Algo' ) continua o problema.
Deu o mesmo erro novamente.

Traceback:

File "C:/works/test_tkinter/cadastro_entrega.py", line 6, in salvar_dados
    dados.write(u'Nome: %s\n' % unicode(nome.get()))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)

Maxwell Morais

unread,
Dec 14, 2012, 12:22:37 PM12/14/12
to python...@googlegroups.com
@Mário, @Luciano

Eu resolvi testar o teu código aqui e realmente tive o mesmo erro.
Achei estranho pois a única diferença é que eu uso sqlite e vc está utilizando txt, pesquisando na net[1] eu descobri que é um erro padrão do python, que reporta UnicodeDecodeError, toda vez que você tenta enviar uma string unicode para um arquivo com open.

A forma de contonar isto é com u"".encode('utf-8'), mas é estranho este comportamento, preciso dar uma olhada na documentação, para compreender isto.

Luciano Ramalho

unread,
Dec 14, 2012, 12:31:26 PM12/14/12
to python...@googlegroups.com
Eu não tenho tempo de analisar com mais detalhe este caso, mas o mais
provável é que a função nome.get esteja devolvendo uma str utf-8,
então você precisa converter isso explicitamente para unicode, assim:

nome.get().decode('utf-8')

Na verdade, qual o encoding usado vai depender da API e do SO. No
Windows pode ser que o encoding devolvido pelo Tkinger seja 'cp1252'.
No Linux há muitos anos já é 'utf-8'.

Luciano Ramalho

unread,
Dec 14, 2012, 12:35:01 PM12/14/12
to python...@googlegroups.com
2012/12/14 Maxwell Morais <max.mor...@gmail.com>
>
> @Mário, @Luciano
>
> Eu resolvi testar o teu código aqui e realmente tive o mesmo erro.
> Achei estranho pois a única diferença é que eu uso sqlite e vc está
> utilizando txt, pesquisando na net[1] eu descobri que é um erro padrão do
> python, que reporta UnicodeDecodeError, toda vez que você tenta enviar uma
> string unicode para um arquivo com open.
>
> A forma de contonar isto é com u"".encode('utf-8'), mas é estranho este
> comportamento, preciso dar uma olhada na documentação, para compreender
> isto.

Não é estranho isso, é perfeitamente compreensível desde que se
entenda os fundamentos do Unicode. Basicamente, não existem arquivos
em formato "unicode", esta é apenas uma forma de representar strings
em memória. No disco (e na rede) os dados invariavelmente são
codificados para algum formato específico de bytes. Utf-8 é um desses
formatos.

Juro que um dia eu vou dedicar umas horas a explicar isso, só não sei quando.

Me dá desespero ver o quanto esse assunto causa problemas e quantas
vezes as pessoas aqui na lista dão respostas baseadas em mandingas e
superstições (não estou falando de vc, OK, Maxwell?).

[ ]s
Luciano

Mário Neto

unread,
Dec 14, 2012, 12:42:01 PM12/14/12
to python...@googlegroups.com
Opa, obg pelo apoio pessoal, a solução foi usar o módulo codecs pra abrir o arquivo passando o encoding como abaixo:

import codecs
with codecs.open('dados.txt', 'a', 'utf-8') as dados:

Não sei se é uma boa prática.

Mário Neto

unread,
Dec 14, 2012, 12:51:07 PM12/14/12
to python...@googlegroups.com
Aproveitando o tkinter:
da pra capturar o seguinte evento:
- Ao digitar um texto no campo "nome"
- Mudar o conteúdo do texto "custom_msg"
- com custom_msg.set('Dados salvos com sucesso!')

??

Nota: Nunca havia feito nada com Python e GUI Desktop, é surpreendente a limpeza do código usando o Tkinter =)

Luciano Ramalho

unread,
Dec 14, 2012, 1:10:42 PM12/14/12
to python...@googlegroups.com
2012/12/14 Mário Neto <macnd...@gmail.com>:
> Opa, obg pelo apoio pessoal, a solução foi usar o módulo codecs pra abrir o
> arquivo passando o encoding como abaixo:
>
> import codecs
> with codecs.open('dados.txt', 'a', 'utf-8') as dados:
>
> Não sei se é uma boa prática.

Sim, é uma boa prática. Melhor ainda é usar a função io.open, que é um
backport do Python 3, desta forma vc fica mais preparado para o
futuro.

[ ]s
Luciano

Mário Neto

unread,
Dec 14, 2012, 1:16:39 PM12/14/12
to python...@googlegroups.com
Humm.. mt bom, não sabia.

Sobre o evento usei:

def key_nome(e):
    custom_msg.set('Cadastre os dados de entrega.')

nome.bind('<Key>', key_nome)

Isso foi muito prático, más sempre quando digito ele executa, Tem como executar o bind só 1 vez?

Mário Neto

unread,
Dec 14, 2012, 1:19:11 PM12/14/12
to python...@googlegroups.com
ahh. com o módulo io ele salvou com caracteres estranho, mas isso deve ser apenas um pequeno problema apenas de passar unicode explicitamente =)

Nome: m�rio

Maxwell Morais

unread,
Dec 14, 2012, 1:40:40 PM12/14/12
to python...@googlegroups.com
É justamente por que sua string também precisa ser codificada como utf-8 antes de escrevê-la no arquivo.

Portanto, adicione:
mystring = u"Nome: %s"% nome.get()
write(mystring.encode('utf-8'))

se você preferir reduzir o tamanho do código, você pode colocar a coerção da string entre parenteses e acessar o método encode do objeto retornado assim:

write((u"Nome: %s"%nome.get()).encode('utf-8'))

Álvaro Justen [Turicas]

unread,
Dec 14, 2012, 2:14:51 PM12/14/12
to python...@googlegroups.com
2012/12/14 Maxwell Morais <max.mor...@gmail.com>
> É justamente por que sua string também precisa ser codificada como utf-8
> antes de escrevê-la no arquivo.
>
> Portanto, adicione:
> mystring = u"Nome: %s"% nome.get()
> write(mystring.encode('utf-8'))

Esse código também está errado, veja:
>>> u'Nome: %s' % 'Álvaro'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position
0: ordinal not in range(128)

O que acontece acima é que você está tentando colocar uma sequência de
bytes ('Álvaro', que é do tipo 'str') dentro de um objeto unicode
através do operador '%' (que existe tanto para 'str' quanto para
'unicode'). Na minha visão, o Python poderia ser mais explícito, nesse
caso. Para mim, o ideal seria ele levantar uma exceção do tipo
TypeError (não dá pra operar 'unicode' com 'str', pois isso pode
causar *muitos* erros).
Isso dá erro porque o Python tenta decodar o conjunto de bytes usando
o codec 'ascii' (que é o padrão) e, como 'Á' não está disponível na
tabela ASCII, ele gera essa exceção. O correto seria eu decodificar
utilizando um codec que possui esse símbolo (e mais: um codec que
representa esse símbolo com os mesmos bits que estão no código abaixo,
que no caso foi escrito usando UTF-8), como abaixo:

>>> u'Nome: %s' % 'Álvaro'.decode('utf-8')
u'Nome: \xc1lvaro'

Como o operador '%' está depreciado, o melhor seria usar o método format:

>>> u'Nome: {}'.format('Álvaro'.decode('utf-8'))
u'Nome: \xc1lvaro'


Eu dei uma palestra na PythonBrasil[8] sobre Unicode, os slides estão
disponíveis em:
http://turicas.info/slides/python-unicode

Em muito breve (próximos dias) abrirei um curso online sobre o
assunto[http://www.pingmind.com/python-unicode/] (utilizando a
plataforma PyCursos/PingMind) e também postarei o vídeo de uma
palestra de 1h que falo sobre o assunto (na PythonBrasil[8] só tive
30min), daí publico os links aqui na lista.

[]s
--
Álvaro Justen "Turicas"
http://blog.justen.eng.br http://twitter.com/turicas
http://CursoDeArduino.com.br http://github.com/turicas
+55 21 9898-0141

Gladson Simplício Brito

unread,
Dec 14, 2012, 2:33:14 PM12/14/12
to Python Brasil
Acho que poderia fazer assim...
Não sei se é a melhor escolha, pode alguém com mais experiencia comentar:



Gladson Simplício Brito

unread,
Dec 14, 2012, 2:44:40 PM12/14/12
to Python Brasil
foi mal, procurando achei sobre o assunto, aqui:

Álvaro Justen [Turicas]

unread,
Dec 14, 2012, 2:52:38 PM12/14/12
to python...@googlegroups.com
2012/12/14 Gladson Simplício Brito <gladso...@gmail.com>:
> Acho que poderia fazer assim...
> Não sei se é a melhor escolha, pode alguém com mais experiencia comentar:
>
> https://gist.github.com/4287953

O normalize não muda o tipo do objeto e ele requer que a entrada seja
do tipo unicode. A única coisa que a normalização NFKD faz é trocar os
"símbolos embutidos" (como o "Á") por símbolos compostos (acento + A),
porém, como falei, o tipo do objeto continua sendo unicode.

Uma solução para o problema está em:
https://gist.github.com/4288101

Notem que o Tkinter já retorna objetos unicode (o que é esperado de
uma biblioteca -- seria muito ruim se tivéssemos que adivinhar o codec
e fazer o decode "na mão" de tudo que ele retorna).

Gladson Simplício Brito

unread,
Dec 14, 2012, 3:01:26 PM12/14/12
to Python Brasil
Legal, valew @Álvaro Justen


Mário Neto

unread,
Dec 15, 2012, 8:01:09 PM12/15/12
to python...@googlegroups.com
Obrigado Mestres! Belas dicas!
Acabei lendo a apresentação do Álvaro e decidi usar o Python 3.3 =), fiz algumas alterações no código pra deixa-lo mais elegante retirando os ajustes que eram necessários pro Python 2.7.

Segue o código atual:

Grato!
Mário

Adorilson Bezerra de Araujo

unread,
Dec 26, 2012, 9:22:46 PM12/26/12
to python...@googlegroups.com
Em 14 de dezembro de 2012 14:35, Luciano Ramalho <luc...@ramalho.org> escreveu:
2012/12/14 Maxwell Morais <max.mor...@gmail.com>
>
> @Mário, @Luciano
>
> Eu resolvi testar o teu código aqui e realmente tive o mesmo erro.
> Achei estranho pois a única diferença é que eu uso sqlite e vc está
> utilizando txt, pesquisando na net[1] eu descobri que é um erro padrão do
> python, que reporta UnicodeDecodeError, toda vez que você tenta enviar uma
> string unicode para um arquivo com open.
>
> A forma de contonar isto é com u"".encode('utf-8'), mas é estranho este
> comportamento, preciso dar uma olhada na documentação, para compreender
> isto.

Não é estranho isso, é perfeitamente compreensível desde que se
entenda os fundamentos do Unicode. Basicamente, não existem arquivos
em formato "unicode", esta é apenas uma forma de representar strings
em memória. No disco (e na rede) os dados invariavelmente são
codificados para algum formato específico de bytes. Utf-8 é um desses
formatos.

Juro que um dia eu vou dedicar umas horas a explicar isso, só não sei quando.


 

Me dá desespero ver o quanto esse assunto causa problemas e quantas
vezes as pessoas aqui na lista dão respostas baseadas em mandingas e
superstições (não estou falando de vc, OK, Maxwell?).

[ ]s
Luciano


[]'s
Adorilson

Luciano Ramalho

unread,
Dec 27, 2012, 1:29:19 PM12/27/12
to python...@googlegroups.com
2012/12/27 Adorilson Bezerra de Araujo <ador...@gmail.com>:
> Em 14 de dezembro de 2012 14:35, Luciano Ramalho <luc...@ramalho.org>
> escreveu:
>> Juro que um dia eu vou dedicar umas horas a explicar isso, só não sei
>> quando.
>
> Ué, Luciano, mas você não já fez isso?
>
> https://groups.google.com/forum/#!msg/django-brasil/tT4Xa_h1qsA/LmuAPpwLSI0J

Adorilson, muito grato por recuperar esta mensagem sobre Unicode que
mandei lá na django-brasail! Realmente, custou umas duas horas
escrevê-la...

Vou dar uma revisada e publicar em outro lugar mais fácil de achar.

Valeu, Adorilson!

[ ]s
Luciano


>
>
>
>>
>>
>> Me dá desespero ver o quanto esse assunto causa problemas e quantas
>> vezes as pessoas aqui na lista dão respostas baseadas em mandingas e
>> superstições (não estou falando de vc, OK, Maxwell?).
>>
>> [ ]s
>> Luciano
>>
>
> []'s
> Adorilson
>

Mário Neto

unread,
Dec 27, 2012, 2:39:44 PM12/27/12
to python...@googlegroups.com
Um artigo lindo daqueles (como a docs traduzida do Py2.7) viria bem a calhar! =D
Reply all
Reply to author
Forward
0 new messages