--
Alexandre Carneiro
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
,-----------------------------------------------------------.
| Antes de enviar um e-mail para o grupo leia: |
| http://www.pythonbrasil.com.br/moin.cgi/AntesDePerguntar |
| E se você é usuário do BOL lembre-se de cadastrar o |
| e-mail do grupo na lista branca do seu sistema anti-spam. |
`-----------------------------------------------------------´Links do Yahoo! Grupos
<*> Para visitar o site do seu grupo na web, acesse:
http://br.groups.yahoo.com/group/python-brasil/
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@yahoogrupos.com.br
<*> O uso que você faz do Yahoo! Grupos está sujeito aos:
http://br.yahoo.com/info/utos.html
Esses caracteres não são exatamente "ilegais" não. Qual erro está
dando? Mostre o stacktrace completo aí pra ajudar! De repente seria mais
elegante corrigir o problema exato.
Mas respondendo à sua pergunta... pra saber se algum caractere de uma
string não é ASCII, às 3:15 da madrugada, eu faria assim:
import string
def tem_caractere_ilegal(s):
return any(c not in string.ascii_letters for c in s)
--
[]s, Narcélio
Realmente o any é bem elegante preciso aprender/acostumar a usar esses
recursos, inicialmente eu faria assim:
try:
str(u"química")
except UnicodeEncodeError:
raise "NON-ASCII" # Sua exception
Concordo!
> Mas respondendo à sua pergunta... pra saber se algum caractere de uma
> string não é ASCII, às 3:15 da madrugada, eu faria assim:
>
> import string
>
> def tem_caractere_ilegal(s):
> return any(c not in string.ascii_letters for c in s)
Muito bom exemplo de uso da função any, Narcélio.
Por sinal, pessoal, vale a pena notar as funções embutidas any, all e
sum que existem no Python há relativamente pouco tempo e permitem um
estilo de programação funcional bem esperto e legível.
A única coisa que eu não faria igual é o nome da função: eu chamaria
ela de nao_ascii, para não repetir a idéia de que caracteres
acentuados são ilegais por algum motivo. Legalize-it!
[ ]s
Luciano
Dica, se você quiser ignorar esses caracteres não ascii utilize a
normalize do unicodedata.
>>> from unicodedata import normalize
>>> def nfkd(st):
... return normalize('NFKD',
st.decode('iso-8859-1')).encode('ascii', ''ignore')
--
Até mais e boa sorte,
Nycholas de Oliveira e Oliveira.
Este exemplo tem alguns defeitos, Danilo.
Primeiro, normalmente você vai querer testar uma variável, e não uma
constante, certo, então uma função completa seria assim:
#!/usr/bin/env python
# coding: utf-8
def ascii_puro(s): # codigo errado, não copie sem entender!!!
try:
str(s)
except UnicodeEncodeError:
return False
return True
Só que se você testar assim, vai ter o seguinte resultado:
print ascii_puro('a')
print ascii_puro('á')
print ascii_puro(u'a')
print ascii_puro(u'á')
True
True
True
False
Ou seja, 'á' foi considerado ASCII puro, e não é... O problema é o que
o seu método depende do tipo exato da string, se é str ou unicode, e
ainda depende do encoding default to Python, que no Python 2 é ASCII
mas no 3 é UTF-8, então é uma solução muito frágil. Para fazer
funcionar, fica assim:
#!/usr/bin/env python
# coding: utf-8
def ascii_puro(s):
if type(s) is type(u''):
try:
str(s)
except UnicodeEncodeError:
return False
return True
else:
try:
unicode(s)
except UnicodeDecodeError:
return False
return True
print ascii_puro('a')
print ascii_puro('á')
print ascii_puro(u'a')
print ascii_puro(u'á')
Saída:
True
False
True
False
Mas ainda assim estamos contando com o encoding default, então
realmente contar com estes erros não é o canal. Uma alternativa usando
exceções de forma mais segura seria esta:
def ascii_puro(s):
try:
s.encode('ascii')
except (UnicodeEncodeError, UnicodeDecodeError):
return False
return True
A vantagem aqui é que o encoding 'ascii' está sendo mencionado
explicitamente, o que é importante porque no Python 3 o encoding
padrão deixa de ser ascii e passa a ser UTF-8, então muitos problemas
com acentos que nós temos hoje vão desaparecer, e a solução do Danilo
apresentaria outro problema.
O método encode é implementado em C, então tem alto desempenho, mas
expressões geradoras (como na solução do Narcélio) também tẽm alto
desempenho.
O Ricbit ou o Dorneles podem dar uma solução em 7 caracteres, mas aí
eu não sei se vamos entender ;-).
[ ]s
Luciano
Isso não vai apenas ignorar os caracteres não-ascii, ele vai remover
os acentos e cedilha.
Ademilson Ferreira
Isso vai ser muito útil pra eu mudar os nomes de uns mp3 que aparecem
errado no display do player do meu carro. =)
>
> Ademilson Ferreira
>
>
--
Henrique Baggio
Computer Engineering - Unicamp
AAACEC - Atlética da Ciência e Engenharia de Computação
Gestão 2009 - Diretoria do 100Nossão
www.ic.unicamp.br/~aaacec
Microsoft Innovation Center - Unicamp
Software Engineer
http://www.lms.ic.unicamp.br
http://lmsu.codeplex.com
Justamente, Ademilson. Caracteres acentuados e cedilhas são não-ASCII.
A tabela ASCII não tem nenhum caractere acentuado.
Dá uma lida aqui:
http://blog.ramgarlic.com/2009/06/o-diabo-da-acentuacao.html
[ ]s
Luciano
no terminal do linux:
$ pdftk química\ I.pdf química\ II.pdf cat output joined.pdf
Error: Failed to open PDF file:
química I.pdf
Error: Failed to open PDF file:
química II.pdf
Errors encountered. No output created.
Done. Input errors, so no output created.
como o problema é do pdftk, o que eu quero é detectar se o nome do arquivo
tem caracteres acentuados e mostrar uma mensagem para renomear os arquivos.
pergunta de leigo: se o nome do arquivo tem caracteres acentuados significa
que ele está codificado com utf-8??
2009/7/30 Luciano Ramalho <ram...@gmail.com>
>
>
> 2009/7/30 Ademilson Ferreira <ademi...@gmail.com<ademilsonfp%40gmail.com>
> >:
>
> > 2009/7/30 Nycholas de Oliveira e Oliveira <nych...@gmail.com<nycholas%40gmail.com>
> >:
> >>
> >>
> >> :)),
> >>
> >> Dica, se você quiser ignorar esses caracteres não ascii utilize a
> >> normalize do unicodedata.
> >>
> >>>>> from unicodedata import normalize
> >>>>> def nfkd(st):
> >> ... return normalize('NFKD',
> >> st.decode('iso-8859-1')).encode('ascii', ''ignore')
> >>
> >> ...
> >
> > Isso não vai apenas ignorar os caracteres não-ascii, ele vai remover
> > os acentos e cedilha.
>
> Justamente, Ademilson. Caracteres acentuados e cedilhas são não-ASCII.
> A tabela ASCII não tem nenhum caractere acentuado.
>
> Dá uma lida aqui:
>
> http://blog.ramgarlic.com/2009/06/o-diabo-da-acentuacao.html
>
> [ ]s
> Luciano
>
>
--
Alexandre Carneiro
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
não entendi muito bem o uso da função any, mas aqui não funcionou.
>>> import string
>>> def acento(s):
... return any(c not in string.ascii_letters for c in s)
...
>>> s1 = 'química I.pdf'
>>> acento(s1)
True
>>> s2 = 'química II.pdf'
>>> acento(s2)
True
>>> s3 = 'quimica III.pdf' # esse não deveria dar false?
>>> acento(s3)
True
--
Alexandre Carneiro
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
O string.ascii_letters contém apenas as letras, portanto um espaço não é
tratado como ascii nesse caso. Portanto essa solução funciona para uma
palavra só. Dá pra fazer algo como string.ascii_letters + ' ' para aceitar
espaços, mas outros caracteres devem ser aceitos também, né? Ponto,
underscore, hifen...
[]s
Iuri
2009/7/31 alexandre <alex...@gmail.com>
Talvez o string.printable talvez resolva seu problema.
>>> string.printable
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:
;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
Ele possui alguns caracteres inválidos em nomes de arquivo, mas supondo que
suas entradas são nomes de arquivos válidos, isso não é um problema.
def arquivo_nao_ascii(s):
return any(c not in string.printable for c in s)
[]s
Iuri
2009/7/31 Iuri <iuris...@gmail.com>
def tem_caractere_ilegal(s):
return any(c not in string.ascii_letters for c in s)
À primeira vista, pode parecer que a função é ineficiente, pois ela
"parece" montar uma lista de True e False, para depois avaliar se há
algum True. Mas não é assim que funciona. A função do meio é um
generator, ou seja, ela vai gerando um termo por vez, e o any vai
verificando se o termo é verdadeiro, e no primeiro que for, ele já sai
da função.
Para ilustrar, tente entender porque, no exemplo abaixo, o primeiro
entra em loop infinito, enquanto que o segundo chega na resposta
rapidamente.
>>> from itertools import count
>>> any([x == 20 for x in count()])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
>>> any(x == 20 for x in count())
True
>>>
--
Alexandre Martani - amartani em gmail com
Sent from Sao Paulo, SP, Brazil
2009/7/31 Iuri <iuris...@gmail.com>:
E como exatamente você está fazendo essa chamada? Será que a culpa
não é do espaço? Será que não precisa usar o encode no nome do arquivo?
subprocess.call(['pdftk', arquivo.encode('utf8')])
> como o problema é do pdftk, o que eu quero é detectar se o nome do
> arquivo tem caracteres acentuados e mostrar uma mensagem para renomear
> os arquivos. pergunta de leigo: se o nome do arquivo tem caracteres
> acentuados significa que ele está codificado com utf-8??
Depende da configuração do seu sistema. No meu tudo é UTF-8 pra
facilitar. Mas é comum sistemas no Brasil serem Latin-1 (ou ISO-8859-1).
No python, eu acho que a regra é algo assim:
1) LOGO DEPOIS de ler uma string do sistema -- seja do sistema de
arquivos, do usuário, da rede ou do banco de dados -- decodifique com:
sua_string = sua_string.decode('codificacao').
2) Trabalhe com o objeto, que agora é unicode, no seu código normalmente;
3) ANTES de escrever no sistema -- seja no sistema de arquivos, na tela,
na rede ou no banco de dados -- recodifique com:
sua_string = sua_string.encode('codificacao')
Ou seja:
# lendo uma string
nome = raw_input()
# decodificando
nome = nome.decode('utf8')
# seu programa complexo aqui que modifica a string
nome = nome.title()
# recodificando
nome = nome.encode('utf8')
# escrevendo de volta pro sistema
print nome
É isso mesmo? Eu sempre apanho dos encodings...
--
[]s, Narcélio
Basta ler em inglês mesmo:
any(char not in string.ascii_letters for char in string)
=
Algum caracter não está na string.ascii_letter para todo caracter na string?
> mas aqui não funcionou.
Não funcionou porque eu fico respondendo os emails da lista às 3 da
madrugada sem testar direito os snippets... deixo isso a cargo do
leitor... >:^)
Mas como o Iuri disse, pra esse caso a ascii_letters não serve, pois
nela só tem as letras ascii. Um arquivo, dependendo do sistema
operacional, pode ter vários outros caracteres válidos (como o espaço,
hífen, underscore, etc).
--
[]s, Narcélio
E se for o caso, ele ainda pode usar a os.path.isfile():
def arquivo_invalido_segundo_o_julgamento_do_alexandre(filename):
return any(c not in string.printable for c in filename) \
or not os.path.isfile(filename)
--
[]s, Narcélio
Exato! E me entristeço muito quando vejo alguém que reclama da
característica "multi-paradigma" do Python.
Ter listas, dicionários e estas funções embutidas na linguagem é uma
vantagem tremenda! E muitos desenvolvedores ainda não perceberam como é
freqüente termos que lidar com problemas que podem ser tratados de forma
simples e *clara* com construções do paradigma funcional. Por exemplo:
Requisito: "Somar o salário dos gerentes no sistema"
Código: sum(func.salario for func in funcionarios if func.tipo == 'gerente')
A maioria deve fazer isso com um for de 4 linhas.
Até o lambda cabe aqui ou ali de vez em quando. E códigos que usem
map() e reduce() já estão prontinhos para a "nuvem"...
--
[]s, Narcélio
Seria legal ver isso :)
def ascii_puro(s):
return not [c for c in s if ord(c) > 127]
print ascii_puro('a')
print ascii_puro('á')
print ascii_puro(u' a')
print ascii_puro(u'á ')
True
False
True
False
[]s
como a discussão está disvirtuando pra outra coisa que não é a solução
do seu problema, vou tentar ajudar aqui:
dependendo do seu volume de dados, eu faria o seguinte, copie o
arquivo química pra uma pasta temp e guarde sua relação química 1 =
axDds.pdf, faça o mesmo com o quimica 2, e manda o seu programinha de
pdf juntar esses arquivos temporários sem acentos, que você acha?
depois você deleta os pdfs temporários, daí você salva com o nome que
quiser o arquivo até com acento, pois pelo que você está reclamando é
o programinha de juntar pdf que não gosta de arquivos acentuados
exatamente!
vou testar a sua sugestão.
mas como os pdf são grandes vou ter de testar a acentuação antes de partir
pra cópia.
talvez se eu guardasse os nomes dos arquivos, renomea-se, fizesse o joiner e
depois renomea-se novamente com os nomes originais...
acho que teria menos impacto nos recursos do sistema.
--
Alexandre Carneiro
[As partes desta mensagem que não continham texto foram removidas]
------------------------------------
Entendi, eu quis dizer é q o caracter vai desacentuar. O normalize faz
com que os caracteres acentuados "sejam separados dos acentos" (não
sei se é a melhor forma para descrever o comportamento).
Ademilson Ferreira
>>> def has_unicode(s):
... return not unicode(s, errors='ignore') == s
...
>>> has_unicode('química')
True
>>> has_unicode('quimica')
False
Caio Ariede
http://caioariede.com/
2009/7/31 Luiz Eduardo Borges <lu...@yahoo.com.br>:
>> dependendo do seu volume de dados, eu faria o seguinte, copie o
>> arquivo química pra uma pasta temp e guarde sua relação química 1 =
>> axDds.pdf, faça o mesmo com o quimica 2, e manda o seu programinha de
>> pdf juntar esses arquivos temporários sem acentos, que você acha?
>>
>> depois você deleta os pdfs temporários, daí você salva com o nome que
>> quiser o arquivo até com acento, pois pelo que você está reclamando é
>> o programinha de juntar pdf que não gosta de arquivos acentuados
>>
> exatamente!
>
> vou testar a sua sugestão.
> mas como os pdf são grandes vou ter de testar a acentuação antes de
> partir
> pra cópia.
>
> talvez se eu guardasse os nomes dos arquivos, renomea-se, fizesse o
> joiner e
> depois renomea-se novamente com os nomes originais...
> acho que teria menos impacto nos recursos do sistema.
O que eu já pensei uma vez era dentro da aplicação que gera esses
arquivos pegar o nome em unicode, fazer o encoding pra utf-8 e depois
fazer um base64 no nome para nomear num sistema de arquivos. É chato
pois todos lendo o arquivo tem q fazer o base64, mas evita que um
sistema de arquivos com encoding mal configurado estrague o nome dos
arquivos.
Provavelmente ninguém nunca fez isso porque em aplicações maiores
sempre é usado um banco de dados que guarda o nome do arquivo e os
arquivos no disco geralmente são uma hash do nome ou algo sem nehuma
relação com o nome.
--
Leonardo Santagada
santagada at gmail.com
>
> dependendo do seu volume de dados, eu faria o seguinte, copie o
>> arquivo química pra uma pasta temp e guarde sua relação química 1 =
>> axDds.pdf, faça o mesmo com o quimica 2, e manda o seu programinha de
>> pdf juntar esses arquivos temporários sem acentos, que você acha?
>>
>> depois você deleta os pdfs temporários, daí você salva com o nome que
>> quiser o arquivo até com acento, pois pelo que você está reclamando é
>> o programinha de juntar pdf que não gosta de arquivos acentuados
>>
>
>
>
>
>
>
>
>
>
>
>
> exatamente!
>
> vou testar a sua sugestão.
> mas como os pdf são grandes vou ter de testar a acentuação antes de partir
> pra cópia.
>
> talvez se eu guardasse os nomes dos arquivos, renomea-se, fizesse o joiner
> e depois renomea-se novamente com os nomes originais...
> acho que teria menos impacto nos recursos do sistema.
>
>
> --
> Alexandre Carneiro
>
agradeço a todos pela aula.
o meu script não ficou tão elegante mas saiu.
from tkMessageBox import *
from Tkinter import *
from subprocess import *
from os.path import *
import os, sys
Tk().withdraw()
def main():
"""
pdftk %files cat output joined.pdf
"""
files = sys.argv[1:]
d = dirname(files[0])
os.chdir(d)
for f in files:
if(unicode(f, errors='ignore') == f):
fren = []
for i,f in enumerate(files):
nome = str(i) + '.pdf'
os.rename(f, nome)
fren.append(nome)
break
if fren:
cmd = ['pdftk'] + fren + ['cat','output',join(d,'joined.pdf')]
else:
cmd = ['pdftk'] + files + ['cat','output',join(d,'joined.pdf')]
r = call(cmd)
if fren:
for i,f in enumerate(files):
os.rename(fren[i], f)
if(r == 0):
showinfo('pdf_joiner.py v0.1', 'Operação realizada com sucesso!')
else:
showerror('erro!', str(r))
if __name__=='__main__':
main()