Como faço para converter o formato de um arquivo de Unicode para ASCII usando Python?
Pergunta
Eu uso uma ferramenta 3o partido que gera um arquivo no formato Unicode. No entanto, eu prefiro que seja em ASCII. A ferramenta não tem configurações para alterar o formato de arquivo.
Qual é a melhor maneira de converter todo o formato de arquivo usando Python?
Solução
Você pode converter o arquivo com bastante facilidade apenas usando a função unicode
, mas você vai correr em problemas com caracteres Unicode sem um equivalente ASCII em linha reta.
Este blog recomenda o módulo unicodedata
, que parece cuidar de aproximadamente converter os caracteres ASCII correspondentes sem valores directos, por exemplo,
>>> title = u"Klüft skräms inför på fédéral électoral große"
é tipicamente convertido em
Klft skrms infr p fdral lectoral groe
que é muito errado. No entanto, utilizando o módulo unicodedata
, o resultado pode ser muito mais próximo do texto original:
>>> import unicodedata
>>> unicodedata.normalize('NFKD', title).encode('ascii','ignore')
'Kluft skrams infor pa federal electoral groe'
Outras dicas
Penso que esta é uma questão mais profunda do que você imagina . Basta mudar o arquivo de Unicode para ASCII é fácil, no entanto, recebendo todos os caracteres Unicode para traduzir em contrapartes ASCII razoáveis ??(muitas cartas não estão disponíveis em ambas as codificações) é outra.
Este tutorial Python Unicode pode lhe dar uma melhor idéia do que acontece com cadeias de caracteres Unicode que são convertidos para ASCII: http://www.reportlab.com/i18n/python_unicode_tutorial.html
Aqui está uma citação útil a partir do site:
Python 1.6 também recebe um "unicode" built-in função, para a qual você pode especificar a codificação:
> >>> unicode('hello') u'hello'
> >>> unicode('hello', 'ascii') u'hello'
> >>> unicode('hello', 'iso-8859-1') u'hello'
> >>>
Todos os três destes retornar o mesmo coisa, já que os personagens de 'Olá' são comuns a todas as três codificações.
Agora vamos codificar algo com um sotaque europeu, que está fora de ASCII. O que você vê em um console pode depender do seu sistema operacional localidade; Windows permite que me digitar ISO-Latin-1.
> >>> a = unicode('André','latin-1')
> >>> a u'Andr\202'
Se você não pode digitar uma letra aguda e, você pode digitar o string 'Andr \ 202', que é inequívoca.
Unicode suporta todos os comum operações tais como iteração e divisão. Não vamos passar por cima deles aqui.
A propósito, estes é uma iconv
comando linux para fazer este tipo de trabalho.
iconv -f utf8 -t ascii <input.txt >output.txt
Aqui está um código simples (e estúpido) para fazer codificação de tradução. Estou assumindo (mas você não deve) que o arquivo de entrada é em UTF-16 (Windows chama isso simplesmente 'Unicode').
input_codec = 'UTF-16'
output_codec = 'ASCII'
unicode_file = open('filename')
unicode_data = unicode_file.read().decode(input_codec)
ascii_file = open('new filename', 'w')
ascii_file.write(unicode_data.write(unicode_data.encode(output_codec)))
Note que isso não vai funcionar se houver quaisquer caracteres no arquivo Unicode que não são também caracteres ASCII. '?' Você pode fazer o seguinte para transformar caracteres não reconhecidos em s:
ascii_file.write(unicode_data.write(unicode_data.encode(output_codec, 'replace')))
Confira os docs para escolhas mais simples. Se você precisa fazer algo mais sofisticado, talvez você queira dar uma olhada no O UNICODE Martelo em o Cookbook Python.
Como esta:
uc = open(filename).read().decode('utf8')
ascii = uc.decode('ascii')
Note, no entanto, que esta vontade falha com uma exceção UnicodeDecodeError
se existem quaisquer caracteres que não podem ser convertidos para ASCII.
EDIT: Como Pete Karl fora apenas pontas, não existe um mapeamento um-para-um de Unicode para ASCII. Assim, alguns personagens simplesmente não pode ser convertido em uma forma de preservação da informação. Além disso, ASCII padrão é mais ou menos um subconjunto de UTF-8, então você realmente não precisa mesmo de fazer qualquer decodificação.
Para o meu problema onde eu só queria ignorar os caracteres não-ASCII e saída apenas somente de saída ascii, o abaixo solução funcionou muito bem:
import unicodedata
input = open(filename).read().decode('UTF-16')
output = unicodedata.normalize('NFKD', input).encode('ASCII', 'ignore')
É importante notar que não existe um formato de arquivo 'Unicode'. Unicode podem ser codificados para bytes de várias maneiras diferentes. Mais comumente UTF-8 ou UTF-16. Você precisa saber qual é a sua ferramenta de 3-parte é saída. Depois de saber que, a conversão entre diferentes codificações é muito fácil:
in_file = open("myfile.txt", "rb")
out_file = open("mynewfile.txt", "wb")
in_byte_string = in_file.read()
unicode_string = bytestring.decode('UTF-16')
out_byte_string = unicode_string.encode('ASCII')
out_file.write(out_byte_string)
out_file.close()
Como observado nas outras respostas, você provavelmente vai querer fornecer um manipulador de erro com o método de codificação. Usando 'substituir' como o manipulador de erro é simples, mas vai mangle seu texto se ele contém caracteres que não podem ser representados em ASCII.
Como outras pôsteres, ASCII é um subconjunto do unicode.
No entanto, se você:
- tem um aplicativo legado
- você não controlar o código para esse aplicativo
- você está certo de sua entrada cai na ASCII subconjunto
Em seguida, o exemplo abaixo mostra como fazê-lo:
mystring = u'bar'
type(mystring)
<type 'unicode'>
myasciistring = (mystring.encode('ASCII'))
type(myasciistring)
<type 'str'>