Błąd kodowania Python Unicode

104

Czytam i analizuję plik Amazon XML i podczas gdy plik XML wyświetla ``, kiedy próbuję go wydrukować, pojawia się następujący błąd:

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

Z tego, co do tej pory przeczytałem w Internecie, błąd wynika z faktu, że plik XML jest w UTF-8, ale Python chce traktować go jako znak zakodowany w ASCII. Czy istnieje prosty sposób, aby usunąć błąd i poprosić mój program o wydrukowanie pliku XML w trakcie jego odczytywania?

Alex B.
źródło
Właśnie szedłem do SO, aby zadać to pytanie. Czy istnieje łatwy sposób na wyczyszczenie sznurka unicode()?
Nick Heiner,
Sprawdź również odpowiedź na powiązane pytanie: „Python UnicodeDecodeError - Czy źle zrozumiałem kodowanie?”
tzot

Odpowiedzi:

193

Prawdopodobnie twój problem polega na tym, że przeanalizowałeś go poprawnie, a teraz próbujesz wydrukować zawartość XML i nie możesz, ponieważ jest tam kilka obcych znaków Unicode. Spróbuj najpierw zakodować swój ciąg znaków Unicode jako ascii:

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

część „ignoruj” powie mu, aby po prostu pomijał te znaki. Z dokumentacji Pythona:

>>> 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;'

Możesz przeczytać ten artykuł: http://www.joelonsoftware.com/articles/Unicode.html , który okazał się bardzo przydatny jako podstawowy poradnik o tym, co się dzieje. Po przeczytaniu przestaniesz czuć się tak, jakbyś tylko zgadywał, jakich poleceń użyć (a przynajmniej mi się to przydarzyło).

Scott Stafford
źródło
1
Próbuję zabezpieczyć następujący ciąg: 'foo „bar bar” df' (zwróć uwagę na cudzysłowy), ale powyższe nadal zawodzi.
Nick Heiner,
@Rosarch: Jak zawodzi? ten sam błąd? Której reguły obsługi błędów użyłeś?
Scott Stafford,
@Rosarch, twój problem jest prawdopodobnie wcześniejszy. Wypróbuj ten kod: # - - coding: latin-1 - - u = u 'foo "bar bar" df' print u.encode ('ascii', 'ignore') Prawdopodobnie było to przekształcanie twojego ciągu znaków w podany Unicode kodowanie określone dla skryptu w języku Python, które spowodowało błąd.
Scott Stafford,
Poszedłem naprzód i uczyniłem mój problem własnym pytaniem: stackoverflow.com/questions/3224427/ ...
Nick Heiner,
1
.encode('ascii', 'ignore')niepotrzebnie traci dane, nawet jeśli środowisko OP może obsługiwać znaki inne niż ASCII (w większości przypadków)
jfs
16

Lepsze rozwiązanie:

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)

Jeśli chcesz przeczytać więcej o tym, dlaczego:

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

Paxwell
źródło
3
To nie pomaga w przypadku problemu z OP: „nie można zakodować znaku u '\ u2019'” . u'\u2019jest już Unicode.
jfs
6

Nie koduj na stałe kodowania znaków swojego środowiska wewnątrz skryptu; zamiast tego drukuj bezpośrednio tekst Unicode:

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

Jeśli wyjście jest przekierowywane do pliku (lub potoku); możesz użyć PYTHONIOENCODINGenvvar, aby określić kodowanie znaków:

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

W przeciwnym razie python your_script.pypowinien działać jak jest - twoje ustawienia regionalne są używane do kodowania tekstu (na check POSIX: LC_ALL, LC_CTYPE, LANGenvvars - zestaw LANGdo UTF-8, jeśli to konieczne).

Aby wydrukować Unicode w systemie Windows, zobacz tę odpowiedź, która pokazuje, jak wydrukować Unicode na konsoli Windows, do pliku lub za pomocą IDLE .

jfs
źródło
1

Doskonały post: 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
źródło
0

Możesz użyć czegoś w formie

s.decode('utf-8')

który skonwertuje zakodowany przez testowanie UTF-8 na ciąg znaków Unicode w Pythonie. Jednak dokładna procedura zależy od tego, w jaki sposób ładujesz i analizujesz plik XML, np. Jeśli nigdy nie masz bezpośredniego dostępu do ciągu XML, może być konieczne użycie obiektu dekodera z codecsmodułu .

David Z
źródło
Jest już zakodowany w UTF-8 Błąd jest konkretnie: myStrings = deque (tekst [u'Dorf i Svoboda \ u2019s opiera się na poddyscyplinach str ... i inżynierii komputerowej. ']) Ciąg jest w UTF-8, widać, ale denerwuje się z powodu wewnętrznego „\ u2019”
Alex B,
Och, OK, myślałem, że masz inny problem.
David Z,
7
@Alex B: Nie, ciąg znaków to Unicode, a nie Utf-8. Aby zakodować to jako użycie Utf-8'...'.encode('utf-8')
sth
0

Napisałem następujące, aby naprawić uciążliwe cytaty spoza ASCII i wymusić konwersję na coś użytecznego.

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
user5910
źródło
0

Jeśli chcesz wydrukować przybliżoną reprezentację ciągu na ekranie, zamiast ignorować te niedrukowalne znaki, wypróbuj unidecodepakiet tutaj:

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

Wyjaśnienie można znaleźć tutaj:

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

Jest to lepsze niż użycie u.encode('ascii', 'ignore')dla danego ciągu znaków ui może uchronić Cię przed niepotrzebnym bólem głowy, jeśli precyzja znaków nie jest tym, czego szukasz, ale nadal chcesz mieć czytelność dla człowieka.

Wirawan

Wirawan Purwanto
źródło
-1

Spróbuj dodać następujący wiersz u góry skryptu Pythona.

# _*_ coding:utf-8 _*_
abnvanand
źródło
-1

Python 3.5, 2018

Jeśli nie wiesz, jakie jest kodowanie, ale parser Unicode ma problemy, możesz otworzyć plik Notepad++i wybrać na górnym pasku Encoding->Convert to ANSI. Następnie możesz napisać swój Python w ten sposób

with open('filepath', 'r', encoding='ANSI') as file:
    for word in file.read().split():
        print(word)
Atomar94
źródło