kodowanie i dekodowanie łańcuchów?

Oto moje próby z komunikatami o błędach. Co robię źle?

string.decode("ascii", "ignore")

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

string.encode('utf-8', "ignore")

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 37: ordinal not in range(128)

Author: martineau, 2012-07-05

4 answers

Nie możesz dekodować unicode, ani nie możesz dekodować str. Spróbuj zrobić to na odwrót .

 82
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-05 07:50:15

Zgadywanie wszystkich rzeczy pominiętych w pierwotnym pytaniu, ale, zakładając Python 2.x kluczem jest uważne odczytanie komunikatów o błędach: w szczególności, gdy wywołujesz "koduj", ale komunikat mówi "dekoduj" i odwrotnie, ale także typy wartości zawartych w komunikatach.

W pierwszym przykładzie string jest typu unicodei próbowano go dekodować, co jest operacją przekształcającą łańcuch bajtów na unicode. Python pomógł w przekonwertowaniu wartości unicode aby str użyć domyślnego kodowania 'ascii', ale ponieważ twój ciąg znaków zawierał znak spoza ascii, wystąpił błąd, który mówi, że Python nie był w stanie zakodować a Unicode wartość. Oto przykład, który pokazuje typ ciągu wejściowego:

>>> u"\xa0".decode("ascii", "ignore")

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    u"\xa0".decode("ascii", "ignore")
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128)

W drugim przypadku wykonujesz odwrotną próbę zakodowania ciągu bajtów. Kodowanie jest operacją, która konwertuje unicode na ciąg bajtów, więc Python pomaga najpierw przekonwertować ciąg bajtów na unicode i, ponieważ nie podano ciągu ascii, domyślny dekoder ascii nie działa:

>>> "\xc2".encode("ascii", "ignore")

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    "\xc2".encode("ascii", "ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)
 59
Author: Duncan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-05 11:02:38

Poza uzyskaniem decode i encode od tyłu, myślę, że częścią odpowiedzi tutaj jest tak naprawdę nie używaj kodowaniaascii . Pewnie nie tego chcesz.

Na początek pomyśl o str Jak o pliku tekstowym. To tylko Banda bajtów bez kodowania. To, jak to jest interpretowane, zależy od tego, jaki fragment kodu go czyta. Jeśli nie wiesz, o czym mówi ten akapit, przeczytaj absolutne Minimum co Programista absolutnie, pozytywnie musi wiedzieć o Unicode i zestawach znaków już teraz, zanim przejdziesz dalej.

Naturalnie, wszyscy jesteśmy świadomi bałaganu, który stworzył. Odpowiedzią jest, przynajmniej w pamięci, posiadanie standardowego kodowania dla wszystkich łańcuchów. I tu wkracza unicode. Mam problem ze znalezieniem dokładnie tego, jakie kodowanie używa Python wewnętrznie na pewno, ale to naprawdę nie ma znaczenia tylko dla tego. Chodzi o to, że wiesz, że jest to ciąg bajtów, który są interpretowane w określony sposób. Więc musisz tylko myśleć o samych znakach, a nie bajtach.

Problem w tym, że w praktyce spotyka się oba. Niektóre biblioteki dają str, a niektóre oczekują str. Z pewnością ma to sens, gdy strumieniujesz serię bajtów (takich jak na lub z dysku lub przez żądanie internetowe). Więc musisz być w stanie tłumaczyć tam iz powrotem.

Enter codecs: jest to biblioteka tłumaczeń między tymi dwoma typami danych. Używasz {[7] } aby wygenerować sekwencję bajtów (str) Z ciągu tekstowego (unicode), a następnie użyć decode aby uzyskać ciąg tekstowy (unicode) z ciągu bajtów (str).

Na przykład:

>>> s = "I look like a string, but I'm actually a sequence of bytes. \xe2\x9d\xa4"
>>> codecs.decode(s, 'utf-8')
u"I look like a string, but I'm actually a sequence of bytes. \u2764"
Co tu się stało? Podałem Pythonowi sekwencję bajtów, a potem powiedziałem: "Daj mi wersję unicode tego, biorąc pod uwagę, że ta sekwencja bajtów jest w 'utf-8'."Stało się tak, jak prosiłem, a te bajty (znak serca ) są teraz traktowane jako całość, reprezentowane przez ich Unicode codepoint.

Chodźmy na odwrót:

>>> u = u"I'm a string! Really! \u2764"
>>> codecs.encode(u, 'utf-8')
"I'm a string! Really! \xe2\x9d\xa4"

Dałem Pythonowi ciąg znaków Unicode i poprosiłem go o przetłumaczenie go na sekwencję bajtów używając kodowania 'utf-8'. Tak się stało, a teraz serce to tylko kilka bajtów, których nie można wydrukować jako ASCII; więc pokazuje mi zamiast tego szesnastkowy.

Możemy oczywiście pracować z innymi kodowaniami:]}
>>> s = "I have a section \xa7"
>>> codecs.decode(s, 'latin1')
u'I have a section \xa7'
>>> codecs.decode(s, 'latin1')[-1] == u'\u00A7'
True

>>> u = u"I have a section \u00a7"
>>> u
u'I have a section \xa7'
>>> codecs.encode(u, 'latin1')
'I have a section \xa7'

('\xa7' jest znakiem sekcji , w obu Unicode i Latin-1.)

Więc dla twoje pytanie, najpierw musisz dowiedzieć się w jakim kodowaniu jest twoje str.

  • Czy to pochodzi z pliku? Z żądania internetowego? Z twojej bazy danych? Następnie źródło określa kodowanie. Znajdź kodowanie źródła i użyj go do przetłumaczenia na unicode.

    s = [get from external source]
    u = codecs.decode(s, 'utf-8') # Replace utf-8 with the actual input encoding
    
  • A może próbujesz to gdzieś napisać. Jakiego kodowania oczekuje miejsce docelowe? Użyj tego, aby przetłumaczyć to na str. UTF-8 jest dobrym wyborem dla zwykłego tekstu dokumenty; większość rzeczy może je odczytać.

    u = u'My string'
    s = codecs.encode(u, 'utf-8') # Replace utf-8 with the actual output encoding
    [Write s out somewhere]
    
  • Czy ty tylko tłumaczysz tam i z powrotem w pamięci dla interoperacyjności czy coś? Następnie wybierz kodowanie i trzymaj się go; 'utf-8' jest prawdopodobnie najlepszym wyborem do tego:

    u = u'My string'
    s = codecs.encode(u, 'utf-8')
    newu = codecs.decode(s, 'utf-8')
    

We współczesnym programowaniu, prawdopodobnie nigdy nie chcesz używać kodowania 'ascii' do tego celu. Jest to bardzo mały podzbiór wszystkich możliwych znaków i żaden system, który znam, nie używa go domyślnie lub cokolwiek.

Python 3 robi wszystko, aby uczynić toogromnie jaśniejszym, po prostu zmieniając nazwy. W Pythonie 3, str został zastąpiony przez bytes, a unicode został zastąpiony przez str.

 24
Author: jpmc26,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-04 04:21:55

To dlatego, że Twój łańcuch wejściowy nie może być przekonwertowany zgodnie z regułami kodowania (domyślnie ścisłymi).

Nie wiem, ale zawsze kodowałem używając bezpośrednio konstruktora unicode (), przynajmniej tak jest w oficjalnej dokumentacji:

unicode(your_str, errors="ignore")
 2
Author: wikier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-05 07:58:02