Jaka jest różnica między kodowaniem / dekodowaniem?

180

Nigdy nie byłem pewien, czy rozumiem różnicę między dekodowaniem i kodowaniem str / unicode.

Wiem, że dzieje się tak, str().decode()gdy masz ciąg bajtów, o którym wiesz, że ma pewne kodowanie znaków, biorąc pod uwagę nazwę kodowania, zwróci ciąg Unicode.

Wiem, że unicode().encode()konwertuje znaki Unicode na ciąg bajtów zgodnie z podaną nazwą kodowania.

Ale nie rozumiem po co str().encode()i po co unicode().decode(). Czy ktoś może wyjaśnić, a być może również poprawić wszystko, co popełniłem powyżej?

EDYTOWAĆ:

Kilka odpowiedzi podaje informacje o tym, co .encoderobi na łańcuchu, ale wydaje się, że .decodenikt nie wie, co robi dla Unicode.

.ıu
źródło
Myślę, że druga odpowiedź na tej stronie jest wystarczająco jasna i zwięzła.
Ben

Odpowiedzi:

106

decodeMetoda ciągów unicode tak naprawdę nie ma żadnych wniosków na wszystkich (chyba że masz jakieś dane inne niż tekst w ciąg Unicode dla jakiegoś powodu - patrz niżej). Myślę, że jest tam głównie z powodów historycznych. W Pythonie 3 całkowicie go nie ma.

unicode().decode()wykona niejawny kodowania z sużyciem domyślnego ASCII) (kodek. Sprawdź to w ten sposób:

>>> s = u'ö'
>>> s.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

>>> s.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

Komunikaty o błędach są dokładnie takie same.

Za str().encode()to na odwrót - próbuje niejawny dekodowanie z sz kodowaniem domyślnym:

>>> s = 'ö'
>>> s.decode('utf-8')
u'\xf6'
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

Używany w ten sposób str().encode()jest również zbędny.

Istnieje jednak inna aplikacja tej drugiej metody, która jest użyteczna: istnieją kodowania , które nie mają nic wspólnego z zestawami znaków, a zatem mogą być stosowane w znaczący sposób do ciągów 8-bitowych:

>>> s.encode('zip')
'x\x9c;\xbc\r\x00\x02>\x01z'

Masz jednak rację: dwuznaczne użycie „kodowania” w obu tych aplikacjach jest ... dziwne. Ponownie, z oddzielnymi bytei stringtypami w Pythonie 3, nie jest to już problemem.


źródło
4
.decode()na łańcuchach Unicode mogą być przydatne np.,print u'\\u0203'.decode('unicode-escape')
jfs
Dobry przykład @JFSebastian w python3 Myślę, że zrobiłbyś:print u'\\u0203'.encode('utf8').decode('unicode-escape')
AJP
1
@AJP: w Pythonie 3:codecs.decode(u'\\u0203', 'unicode-escape')
jfs
@hop: tak. Aby wykryć nieprawidłowe dane i Python 2/3 kompatybilności, łańcuch może być kodowany jawnie przy użyciu asciikodowania:\\u0203\u00e4'.encode('ascii').decode('unicode-escape')
JFS
@hop: Twój pierwszy komentarz (Dlaczego go usunąłeś? Nie usuwaj komentarzy, na które udzielono odpowiedzi) już to powiedział. Moja odpowiedź ( .encode('ascii').decode('unicode-escape')) nie zależy od sys.getdefaultencoding().
jfs
71

Reprezentowanie ciągu Unicode jako ciągu bajtów jest nazywane kodowaniem . Zastosowanie u'...'.encode(encoding).

Przykład:

    >>> u'æøå'.encode ('utf8')
    „\ xc3 \ x83 \ xc2 \ xa6 \ xc3 \ x83 \ xc2 \ xb8 \ xc3 \ x83 \ xc2 \ xa5”
    >>> u'æøå'.encode („latin1”)
    „\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5”
    >>> u'æøå'.encode („ascii”)
    UnicodeEncodeError: Kodek „ascii” nie może kodować znaków w pozycjach 0-5: 
    porządek poza zakresem (128)

Zazwyczaj koduje się ciąg znaków Unicode za każdym razem, gdy trzeba go użyć do operacji we / wy, na przykład przesłać go przez sieć lub zapisać w pliku dyskowym.

Konwersja ciągu bajtów na ciąg Unicode jest znana jako dekodowanie . Użyj unicode('...', encoding)lub „...”. Dekodowanie (kodowanie).

Przykład:

   >>> u'æøå '
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5' # interpreter drukuje obiekt Unicode w ten sposób
   >>> Unicode („\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5”, „latin1”)
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'
   >>> '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'.decode (' latin1 ')
   u '\ xc3 \ xa6 \ xc3 \ xb8 \ xc3 \ xa5'

Zazwyczaj dekodujesz ciąg bajtów za każdym razem, gdy odbierasz dane ciągu z sieci lub z pliku dyskowego.

Wierzę, że w Pythonie 3 są pewne zmiany w obsłudze Unicode, więc powyższe prawdopodobnie nie jest poprawne dla Pythona 3.

Kilka dobrych linków:

Codeape
źródło
6
Nie odpowiedziałeś na pytanie PO. OP chce wiedzieć, co robią str.encode () i unicode.decode (). Właśnie powtórzyłeś to, co stwierdzono w pierwotnym pytaniu.
stuckintheshuck
Świetna odpowiedź na pytanie, dlaczego w praktyce kiedykolwiek miałeś problemy z dekodowaniem i kodowaniem. Nie każda maszyna rozumie ten sam zestaw znaków, ale wszystkie one rozumieją bajty. Kodowanie w bajtach dla języka, który komputery powszechnie rozumieją (i mogą być przesyłane lub zapisywane na dysk), ale dekoduje, kiedy ludzie faktycznie muszą czytać te bajty (np. Po stronie klienta).
Alex Petralia
Fantastyczna odpowiedź! To powinno pójść w górę !!
sandyp 18.10.18
16

anUnicode. kodowania ( „kodowania”) wyniki w ciąg obiektu i może być wywołana na obiekcie unicode

aString. dekodowanie („kodowanie”) powoduje powstanie obiektu Unicode i może być wywoływane z ciągu znaków zakodowanego w danym kodowaniu.


Kilka dodatkowych wyjaśnień:

Możesz utworzyć obiekt Unicode, który nie ma żadnego zestawu kodowania. Sposób, w jaki Python przechowuje je w pamięci, nie stanowi problemu. Możesz go przeszukiwać, dzielić i wywoływać dowolne funkcje manipulowania ciągami.

Ale przychodzi czas, kiedy chcesz wydrukować obiekt Unicode na konsoli lub w pliku tekstowym. Więc musisz go zakodować (na przykład - w UTF-8), wywołujesz kodowanie ('utf-8') i otrzymujesz ciąg z '\ u <someNumber>', który można doskonale wydrukować.

Następnie ponownie - chciałbyś zrobić coś przeciwnego - przeczytaj ciąg znaków zakodowany w UTF-8 i potraktuj go jako Unicode, więc \ u360 będzie jednym znakiem, a nie 5. Następnie dekodujesz ciąg (z wybranym kodowaniem) i zdobądź zupełnie nowy obiekt typu Unicode.

Na marginesie - możesz wybrać kodowanie zboczeńców, takie jak „zip”, „base64”, „rot”, a niektóre z nich będą konwertowane z łańcucha na łańcuch, ale uważam, że najczęstszym przypadkiem jest UTF-8 / UTF-16 i ciąg.

Abgan
źródło
12

mybytestring.encode (somecodec) ma znaczenie dla następujących wartości somecodec:

  • base64
  • bz2
  • zlib
  • klątwa
  • quopri
  • rot13
  • string_escape
  • uu

Nie jestem pewien, do czego służy dekodowanie już zdekodowanego tekstu Unicode. Próbowanie tego przy dowolnym kodowaniu wydaje się zawsze próbować najpierw zakodować z domyślnym kodowaniem systemu.

nosklo
źródło
5

Istnieje kilka kodowań, których można użyć do dekodowania / kodowania od str do str lub od Unicode do Unicode. Na przykład base64, hex lub nawet rot13. Są one wymienione w module kodeków .

Edytować:

Komunikat dekodowania w łańcuchu Unicode może cofnąć odpowiednią operację kodowania:

In [1]: u'0a'.decode('hex')
Out[1]: '\n'

Zwrócony typ to str zamiast Unicode, co moim zdaniem jest niefortunne. Ale kiedy nie wykonujesz właściwego kodowania / dekodowania między str i Unicode, i tak wygląda to na bałagan.


źródło
1
-1: Metoda dekodowania nie jest stosowana do obiektu Unicode. Zamiast tego obiekt unicode jest kodowany jako „ascii”, zanim rozpocznie się operacja dekodowania. Aby udowodnić to twierdzenie, spróbuj u'ã'.decode ('hex') -, który zwraca UnicodeEncodeError
nosklo
2
@nosklo: Masz rację. To, co naprawdę miałem na myśli, to to, że obiekty unicode mają metodę decode (), dzięki czemu możesz również stosować do nich kodeki niekodujące znaków. Cały ten biznes nie kodujący znaków sprawia, że ​​ten interfejs jest bałaganem w Pythonie <3
1

Prosta odpowiedź jest taka, że ​​są one dokładnie przeciwne.

Komputer wykorzystuje bardzo podstawową jednostkę bajtu do przechowywania i przetwarzania informacji; nie ma to znaczenia dla ludzkich oczu.

Na przykład „\ xe4 \ xb8 \ xad \ xe6 \ x96 \ x87” jest reprezentacją dwóch chińskich znaków, ale komputer wie (to znaczy drukuj lub przechowuj) tylko chińskie znaki, gdy otrzymują słownik, aby ich szukać Chińskie słowo, w tym przypadku jest to słownik „utf-8”, i nie pokazałby poprawnie chińskiego słowa, jeśli spojrzysz na inny lub niewłaściwy słownik (przy użyciu innej metody dekodowania).

W powyższym przypadku komputer szuka słowa chińskiego decode().

A proces komputerowego zapisywania Chińczyków w pamięci komputera jest encode().

Zatem zakodowane informacje to nieprzetworzone bajty, a zdekodowane informacje to nieprzetworzone bajty i nazwa słownika, do którego się odwołuje (ale nie sam słownik).

Eren Bay
źródło