Erro de codificação Python Unicode

104

Estou lendo e analisando um arquivo Amazon XML e, embora o arquivo XML mostre um ', quando tento imprimi-lo, recebo o seguinte erro:

'ascii' codec can't encode character u'\u2019' in position 16: ordinal not in range(128) 

Pelo que li online até agora, o erro vem do fato de que o arquivo XML está em UTF-8, mas o Python quer tratá-lo como um caractere codificado em ASCII. Existe uma maneira simples de eliminar o erro e fazer com que meu programa imprima o XML durante a leitura?

Alex B
fonte
Eu estava vindo para o SO para postar esta pergunta. Existe uma maneira fácil de higienizar uma string para unicode()?
Nick Heiner
Verifique também esta resposta a uma pergunta relacionada: “Python UnicodeDecodeError - Estou entendendo mal a codificação?”
tzot

Respostas:

193

Provavelmente, o seu problema é que você o analisou bem e agora está tentando imprimir o conteúdo do XML e não consegue porque existem alguns caracteres Unicode estrangeiros. Tente codificar sua string Unicode como ascii primeiro:

unicodeData.encode('ascii', 'ignore')

a parte 'ignorar' dirá para simplesmente pular esses caracteres. Dos documentos do python:

>>> u = unichr(40960) + u'abcd' + unichr(1972)
>>> u.encode('utf-8')
'\xea\x80\x80abcd\xde\xb4'
>>> u.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in position 0: ordinal not in range(128)
>>> u.encode('ascii', 'ignore')
'abcd'
>>> u.encode('ascii', 'replace')
'?abcd?'
>>> u.encode('ascii', 'xmlcharrefreplace')
'&#40960;abcd&#1972;'

Você pode querer ler este artigo: http://www.joelonsoftware.com/articles/Unicode.html , que achei muito útil como um tutorial básico sobre o que está acontecendo. Após a leitura, você deixará de sentir que está apenas adivinhando quais comandos usar (ou pelo menos isso aconteceu comigo).

Scott Stafford
fonte
1
Estou tentando tornar a seguinte string segura: 'foo “bar bar” df' (observe as aspas curvas), mas o acima ainda falha para mim.
Nick Heiner
@Rosarch: Falha como? mesmo erro? E qual regra de tratamento de erros você usou?
Scott Stafford
@Rosarch, seu problema provavelmente é anterior. Tente este código: # - - coding: latin-1 - - u = u 'foo “bar bar” df' print u.encode ('ascii', 'ignore') Para você, ele provavelmente estava convertendo sua string INTO unicode fornecida a codificação que você especificou para o script Python que gerou o erro.
Scott Stafford
Fui em frente e fiz meu problema em sua própria pergunta: stackoverflow.com/questions/3224427/…
Nick Heiner
1
.encode('ascii', 'ignore')perde dados desnecessariamente, mesmo se o ambiente do OP puder suportar caracteres não ASCII (na maioria dos casos)
jfs
16

Uma solução melhor:

if type(value) == str:
    # Ignore errors even if the string is not proper UTF-8 or has
    # broken marker bytes.
    # Python built-in function unicode() can do this.
    value = unicode(value, "utf-8", errors="ignore")
else:
    # Assume the value object has proper __unicode__() method
    value = unicode(value)

Se você gostaria de ler mais sobre o motivo:

http://docs.plone.org/manage/trouwagen/unicode.html#id1

Paxwell
fonte
3
Isso não ajuda com o problema de OP: "não é possível codificar o caractere u '\ u2019'" . u'\u2019já é Unicode.
jfs
6

Não fixe a codificação de caracteres de seu ambiente dentro de seu script; imprima texto Unicode diretamente em vez disso:

assert isinstance(text, unicode) # or str on Python 3
print(text)

Se sua saída for redirecionada para um arquivo (ou canal); você pode usar PYTHONIOENCODINGenvvar para especificar a codificação de caracteres:

$ PYTHONIOENCODING=utf-8 python your_script.py >output.utf8

Caso contrário, python your_script.pydeve funcionar como é - suas configurações locais são utilizados para codificar o texto (no check POSIX: LC_ALL, LC_CTYPE, LANGenvvars - set LANGa um locale UTF-8 se necessário).

Para imprimir Unicode no Windows, veja esta resposta que mostra como imprimir Unicode no console do Windows, em um arquivo ou usando o IDLE .

jfs
fonte
1

Excelente postagem: http://www.carlosble.com/2010/12/understanding-python-and-unicode/

# -*- coding: utf-8 -*-

def __if_number_get_string(number):
    converted_str = number
    if isinstance(number, int) or \
            isinstance(number, float):
        converted_str = str(number)
    return converted_str


def get_unicode(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode
    return unicode(strOrUnicode, encoding, errors='ignore')


def get_string(strOrUnicode, encoding='utf-8'):
    strOrUnicode = __if_number_get_string(strOrUnicode)
    if isinstance(strOrUnicode, unicode):
        return strOrUnicode.encode(encoding)
    return strOrUnicode
Ranvijay Sachan
fonte
0

Você pode usar algo na forma

s.decode('utf-8')

que irá converter um bytestring codificado em UTF-8 em uma string Python Unicode. Mas o procedimento exato a ser usado depende exatamente de como você carrega e analisa o arquivo XML, por exemplo, se você nunca acessa a string XML diretamente, pode ser necessário usar um objeto decodificador do codecsmódulo .

David Z
fonte
Já está codificado em UTF-8. O erro é especificamente: myStrings = deque ([u'Dorf e Svoboda \ u2019s texto baseia-se nas subdisciplinas str ... e Engenharia da computação \ u2019s. ']) A string está em UTF-8 como você pode ver, mas fica furioso com o interno '\ u2019'
Alex B
Oh, OK, pensei que você estava tendo um problema diferente.
David Z
7
@Alex B: Não, a string é Unicode, não Utf-8. Para codificá- lo como Utf-8, use'...'.encode('utf-8')
sth
0

Escrevi o seguinte para consertar as cotações não-ascii incômodas e forçar a conversão para algo utilizável.

unicodeToAsciiMap = {u'\u2019':"'", u'\u2018':"`", }

def unicodeToAscii(inStr):
    try:
        return str(inStr)
    except:
        pass
    outStr = ""
    for i in inStr:
        try:
            outStr = outStr + str(i)
        except:
            if unicodeToAsciiMap.has_key(i):
                outStr = outStr + unicodeToAsciiMap[i]
            else:
                try:
                    print "unicodeToAscii: add to map:", i, repr(i), "(encoded as _)"
                except:
                    print "unicodeToAscii: unknown code (encoded as _)", repr(i)
                outStr = outStr + "_"
    return outStr
usuário5910
fonte
0

Se você precisar imprimir uma representação aproximada da string na tela, em vez de ignorar os caracteres não imprimíveis, tente o unidecodepacote aqui:

https://pypi.python.org/pypi/Unidecode

A explicação pode ser encontrada aqui:

https://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/

Isso é melhor do que usar o u.encode('ascii', 'ignore')para uma determinada string ue pode evitar dores de cabeça desnecessárias se a precisão do caractere não for o que você procura , mas ainda deseja ter legibilidade humana.

Wirawan

Wirawan Purwanto
fonte
-1

Tente adicionar a seguinte linha no início do seu script Python.

# _*_ coding:utf-8 _*_
Abnvanand
fonte
-1

Python 3.5, 2018

Se você não sabe qual é a codificação, mas o analisador Unicode está tendo problemas, você pode abrir o arquivo Notepad++e selecionar na barra superior Encoding->Convert to ANSI. Então você pode escrever seu python assim

with open('filepath', 'r', encoding='ANSI') as file:
    for word in file.read().split():
        print(word)
Atomar94
fonte