Γιατί το παρακάτω στοιχείο αποτυγχάνει; και γιατί πετυχαίνει με το "latin-1" codec;
o = "a test of \xe9 char" #I want this to remain a string as this is what I am receiving
v = o.decode("utf-8")
οδηγεί σε:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\encodings\utf_8.py",
line 16, in decode
return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError:
'utf8' codec can't decode byte 0xe9 in position 10: invalid continuation byte
Στο δυαδικό σύστημα, το 0xE9 μοιάζει με 1110 1001
. Αν διαβάσετε για το UTF-8 στη Wikipedia, θα δείτε ότι ένα τέτοιο byte πρέπει να ακολουθείται από δύο της μορφής 10xx xxxx
. Έτσι, για παράδειγμα:
>>> b'\xe9\x80\x80'.decode('utf-8')
u'\u9000'
Αλλά αυτό είναι απλώς η μηχανική αιτία της εξαίρεσης. Σε αυτή την περίπτωση, έχετε μια συμβολοσειρά που είναι σχεδόν σίγουρα κωδικοποιημένη σε latin 1. Μπορείτε να δείτε πώς ο UTF-8 και ο latin 1 φαίνονται διαφορετικοί:
>>> u'\xe9'.encode('utf-8')
b'\xc3\xa9'
>>> u'\xe9'.encode('latin-1')
b'\xe9'
(Σημείωση, χρησιμοποιώ ένα μείγμα αναπαράστασης της Python 2 και 3 εδώ. Η είσοδος είναι έγκυρη σε οποιαδήποτε έκδοση της Python, αλλά ο διερμηνέας της Python σας είναι απίθανο να εμφανίζει στην πραγματικότητα τόσο unicode όσο και συμβολοσειρές byte με αυτόν τον τρόπο).
Είναι άκυρο UTF-8. Αυτός ο χαρακτήρας είναι ο χαρακτήρας e-acute στο ISO-Latin1, γι' αυτό και πετυχαίνει με αυτό το σύνολο κωδικών.
Εάν δεν γνωρίζετε το σύνολο κωδικών στο οποίο λαμβάνετε συμβολοσειρές, έχετε πρόβλημα. Το καλύτερο θα ήταν να επιλέξετε ένα μόνο σύνολο κωδικών (ελπίζω UTF-8) για το πρωτόκολλο/την εφαρμογή σας και στη συνέχεια να απορρίπτετε απλώς αυτά που δεν αποκωδικοποιούνται.
Αν δεν μπορείτε να το κάνετε αυτό, θα χρειαστείτε ευρετικές μεθόδους.
Επειδή το UTF-8 είναι multibyte και δεν υπάρχει χαρακτήρας που να αντιστοιχεί στον συνδυασμό του \xe9
και του επόμενου διαστήματος.
Γιατί θα πρέπει να πετύχει τόσο σε και utf-8 όσο και σε latin-1;
Εδώ πώς θα έπρεπε να είναι η ίδια πρόταση σε utf-8:
>>> o.decode('latin-1').encode("utf-8")
'a test of \xc3\xa9 char'