2010-07-11 16 views
14

Eventuali duplicati:
Python UnicodeDecodeError - Am I misunderstanding encode?Python: disinfetti una stringa per unicode?

ho una stringa che sto cercando di fare sicuro per la funzione unicode():

>>> s = " foo “bar bar ” weasel" 
>>> s.encode('utf-8', 'ignore') 

Traceback (most recent call last): 
    File "<pyshell#8>", line 1, in <module> 
    s.encode('utf-8', 'ignore') 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 
>>> unicode(s) 

Traceback (most recent call last): 
    File "<pyshell#9>", line 1, in <module> 
    unicode(s) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 

Sto dando agitando intorno Qui. Cosa devo fare per rimuovere i caratteri non sicuri dalla stringa?

Un po 'correlato a questo question, anche se non sono riuscito a risolvere il mio problema da esso.

Questo fallisce anche:

>>> s 
' foo \x93bar bar \x94 weasel' 
>>> s.decode('utf-8') 

Traceback (most recent call last): 
    File "<pyshell#13>", line 1, in <module> 
    s.decode('utf-8') 
    File "C:\Python25\254\lib\encodings\utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0x93 in position 5: unexpected code byte 
+0

Mi chiedo perché 'str' abbia una funzione' encode' e se il parametro "encoding" specifichi la codifica del risultato, o la codifica dell'input. Che cosa stai tentando di fare esattamente qui? – Thanatos

+0

Si prega di controllare [questo] (http://stackoverflow.com/questions/368805/python-unicodedecodeerror-am-i-misunderstanding-encode/370199#370199) rispondere a una domanda correlata: "Python UnicodeDecodeError - Mi capita di non capire la codifica? " – tzot

+0

Per coloro che cercano una soluzione per disinfettare caratteri speciali unicode in (X) HTML, prova' u'my unicode str'.encode ('ascii', 'xmlcharrefreplace') '. – toszter

risposta

4

EDIT. Sembra che la stringa sia codificata in modo tale che (SIN. DOPPIO CONTRASSEGNO DI DOMOTAZIONE) diventi \x93 e (CONTRASSEGNO DOPPIO DI PREVALENZA DESTRO) diventa \x94. C'è un certo numero di tabelle codici con una tale mappatura, CP1250 è uno di loro, quindi si può usare questo:

s = s.decode('cp1250') 

Per tutte le tabelle codici che mappa -\x93 vedere here (tutti loro mappa anche a \x94 , che può essere verificato here).

+0

Questa chiamata non riesce (vedi sopra) –

+0

@Rosarch OK, ora vedo la stringa originale. Ho aggiornato la risposta (e nel frattempo @darkporter ha trovato la stessa soluzione). – Bolo

+0

Bel collegamento nelle pagine di codice. Sembra che siano tutte varianti su "windows". Se sei "occidentale", direi semplicemente attenersi alla 1252. – jpsimons

37

Buona domanda. I problemi di codifica sono difficili. Iniziamo con "Ho una stringa". Le stringhe in Python 2 non sono realmente "stringhe", sono array di byte. Quindi la tua stringa, da dove viene e in che encoding è? Il tuo esempio mostra le virgolette ricurve nel letterale e non sono nemmeno sicuro di come l'hai fatto. Provo ad incollarlo in un interprete Python, o lo scrivo su OS X con Option- [, e non viene fuori.

Guardando il secondo esempio, si ha un carattere di esadecimale 93. Questo non può essere UTF-8, perché in UTF-8, qualsiasi byte superiore a 127 fa parte di una sequenza multibyte. Quindi immagino che dovrebbe essere Latin-1. Il problema è che x93 non è un personaggio nel set di caratteri Latin-1. C'è questo intervallo "non valido" in Latin-1 da x7f a x9f che è considerato illegale. Tuttavia, Microsoft ha visto quell'intervallo inutilizzato e ha deciso di inserire "virgolette inglesi". In tal modo hanno creato questa codifica simile chiamata "windows-1252", che è come Latin-1 con roba in quell'intervallo non valido.

Quindi, supponiamo che sia windows-1252. E adesso? String.decode converte i byte in Unicode, quindi è quello che vuoi. Il tuo secondo esempio era sulla traccia giusta, ma non è riuscito perché la stringa non era UTF-8. Prova:

>>> uni = 'foo \x93bar bar\x94 weasel'.decode("windows-1252") 
u'foo \u201cbar bar\u201d weasel' 
>>> print uni 
foo “bar bar” weasel 
>>> type(uni) 
<type 'unicode'> 

Questo è corretto, perché l'apertura di citazione ricci è Unicode U + 201C. Ora che hai Unicode, puoi serializzarlo in byte in qualsiasi codifica tu scelga (se devi passarlo attraverso il filo) o semplicemente tenerlo come Unicode se rimane in Python. Se vuoi convertire in UTF-8, usa la funzione oppose, string.encode.

>>> uni.encode("utf-8") 
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel' 

Le virgolette ricce richiedono 3 byte per la codifica in UTF-8. Potresti usare UTF-16 e sarebbero solo due byte. Non puoi codificare come ASCII o Latin-1, perché quelli non hanno virgolette ricci.

+1

+1, ma dovresti anche menzionare che questa risposta è specifica per Python 2.x. In 3.x, il tipo 'str' viene rinominato in' byte' e 'unicode' viene rinominato in' str'. Iniziando a creare confusione all'inizio, questo cambiamento rende meno probabile questo tipo di cose. –

+0

+1 per "iniziamo con" Ho una stringa "" haha ​​ –

+1

@Daniel Non essere incestuoso ma ho appena votato la tua dichiarazione di voto. È vero: quanto sopra è specifico per Python 2.x. – jpsimons

Problemi correlati