UnicodeDecodeError: il codec 'utf8' non può decodificare il byte 0x9c


289

Ho un server socket che dovrebbe ricevere caratteri validi UTF-8 dai client.

Il problema è che alcuni client (principalmente hacker) stanno inviando su di esso tutti i tipi di dati sbagliati.

Sono in grado di distinguere facilmente il client originale, ma sto registrando su file tutti i dati inviati in modo da poterlo analizzare in seguito.

A volte ricevo personaggi come questo œche causano l' UnicodeDecodeErrorerrore.

Devo essere in grado di creare la stringa UTF-8 con o senza quei caratteri.


Aggiornare:

Per il mio caso particolare il servizio socket era un MTA e quindi mi aspetto di ricevere solo comandi ASCII come:

EHLO example.com
MAIL FROM: <john.doe@example.com>
...

Stavo registrando tutto questo in JSON.

Quindi alcune persone là fuori senza buone intenzioni hanno deciso di vendere tutti i tipi di spazzatura.

Ecco perché per il mio caso specifico è perfettamente OK rimuovere i caratteri non ASCII.


1
la stringa esce da un file o un socket? potresti inviare esempi di codice su come la stringa viene codificata e decodificata prima di essere inviata tramite il socket / filehandler?
— devsnd,

Ho scritto o non ho scritto che la stringa arriva al socket? Ho semplicemente letto la stringa dal socket e con per metterla in un dizionario e poi JSON per inviarla. La funzione JSON non è riuscita a causa di quei caratteri.
— transilvlad,

puoi per favore inserire i tuoi dati di esempio del problema
— Shubham Sharma,

Risposte:


343

http://docs.python.org/howto/unicode.html#the-unicode-type

str = unicode(str, errors='replace')

o

str = unicode(str, errors='ignore')

Nota: questo eliminerà (ignorerà) i caratteri in questione restituendo la stringa senza di essi.

Per me questo è il caso ideale poiché lo sto usando come protezione contro input non ASCII che non è consentito dalla mia applicazione.

In alternativa: utilizzare il metodo open dal codecsmodulo per leggere nel file:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:

45
Sì, anche se di solito è una cattiva pratica / pericolosa, perché perderai solo personaggi. Meglio determinare o rilevare la codifica della stringa di input e decodificarla prima in Unicode, quindi codificare come UTF-8, ad esempio:str.decode('cp1252').encode('utf-8')
— Ben Hoyt,

In alcuni casi sì, hai ragione, potrebbe causare problemi. Nel mio caso non mi interessa di loro in quanto sembrano essere caratteri extra provenienti da una cattiva formattazione e programmazione dei client che si collegano al mio server socket.
— transilvlad,

Questo in realtà aiuta se il contenuto della stringa non è effettivamente valido, nel mio caso '\xc0msterdam'che si trasforma in u'\ufffdmsterdam'con sostituzione
— PvdL

3
se sei finito qui perché hai problemi a leggere un file, aprire il file in modalità binaria potrebbe aiutare: open(file_name, "rb")e quindi applicare l'approccio di Ben dai commenti sopra
— kristian

la stessa opzione si applica anche a più, ad esempio a "qualcosa.decode ()"
— Alexander Stohr

83

Cambiare il motore da C a Python ha fatto il trucco per me.

Il motore è C:

pd.read_csv(gdp_path, sep='\t', engine='c')

Il codec 'utf-8' non può decodificare il byte 0x92 in posizione 18: byte iniziale non valido

Engine is Python:

pd.read_csv(gdp_path, sep='\t', engine='python')

Nessun errore per me.


3
questa è in realtà una buona soluzione. non so perché sia ​​stato sottoposto a downgrade.
— ℕʘʘḆḽḘ

Questa potrebbe non essere una buona idea se hai un csvfile enorme . Potrebbe causare un OutOfMemoryerrore o un riavvio automatico del kernel del notebook. Dovresti impostare encodingquesto caso.
— LucasBr

1
Risposta eccellente. Grazie. Questo ha funzionato per me. Avevo "?" All'interno di un personaggio a forma di diamante che stava causando il problema. Con gli occhi chiari ho avuto "" "che è pollici. Ho fatto 2 cose per capire. a) df = pd.read_csv ('test.csv', n_rows = 10000). Questo ha funzionato perfettamente senza il motore. Quindi ho incrementato n_rows per capire quale riga ha avuto un errore. b) df = pd.read_csv ('test.csv', engine = 'python'). Questo ha funzionato e ho stampato la riga errata usando df.iloc [36145], questo mi ha stampato il record errato.
— Jagannath Banerjee,

1
questo ha funzionato anche per me ... Non sono sicuro di ciò che sta accadendo "sotto il cofano" e se questa è in realtà una soluzione bella / buona / corretta in tutti i casi, ma ha fatto il trucco per me;)
— Chrisvdberge

1
Ottima soluzione! Grazie mille.
— Pechi,

62

Questo tipo di problema si risolve per me ora che sono passato a Python 3. Non avevo idea che Python 2 stesse semplicemente rovinando qualsiasi problema con la codifica dei file.

Ho trovato questa bella spiegazione delle differenze e di come trovare una soluzione dopo che nessuna delle precedenti ha funzionato per me.

http://python-notes.curiousefficiency.org/en/latest/python3/text_file_processing.html

In breve, per far sì che Python 3 si comporti nel modo più simile possibile a Python 2, utilizzare:

with open(filename, encoding="latin-1") as datafile:
    # work on datafile here

Tuttavia, leggi l'articolo, non esiste una taglia adatta a tutte le soluzioni.


29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ

16
Sono confuso, come hai scelto cp1252? Ha funzionato per me, ma perché? Non lo so e ora mi sono perso: /. Potresti elaborare? Molte grazie ! :)
— Cirillo N.

4
Potresti presentare un'opzione che funziona per tutti i personaggi? C'è un modo per rilevare i caratteri che devono essere decodificati in modo da poter implementare un codice più generico? Vedo che molte persone lo stanno guardando e scommetto che scartare non è l'opzione desiderata come è per me.
— transilvlad,

Come puoi vedere questa domanda ha abbastanza popolarità. Pensi di poter espandere la tua risposta con una soluzione più generica?
— transilvlad,

13
Non esiste una soluzione più generica per "Indovina la roulette di codifica"
— Puppy,

5
l'ho trovato usando una combinazione di ricerca web, fortuna e intuizione: cp1252 eraused by default in the legacy components of Microsoft Windows in English and some other Western languages
— bolov,

24

Ho avuto lo stesso problema con UnicodeDecodeErrore l'ho risolto con questa linea. Non so se è il modo migliore ma ha funzionato per me.

str = str.decode('unicode_escape').encode('utf-8')

13

il primo, utilizzando get_encoding_type per ottenere il tipo di file di codifica:

import os    
from chardet import detect

# get file encoding type
def get_encoding_type(file):
    with open(file, 'rb') as f:
        rawdata = f.read()
    return detect(rawdata)['encoding']

il secondo, aprendo i file con il tipo:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')

1
cosa succede quando ritorna None
— Chop Labalagun il

3

Nel caso in cui qualcuno abbia lo stesso problema. Sto usando vim con YouCompleteMe , non sono riuscito ad avviare ycmd con questo messaggio di errore, quello che ho fatto è: export LC_CTYPE="en_US.UTF-8"il problema è sparito.


2
Come si collega questo a questa domanda?
— transilvlad

1
Esattamente lo stesso, se sai come funziona youcompleteme. Il plug-in Ycm è architettura socket, la comunicazione tra client e server utilizza socket, entrambi sono moduli Python, non sono in grado di decodificare i pacchetti se l'impostazione di codifica non è corretta
— workplaylifecycle

Ho lo stesso problema. Potete per favore dirmi dove mettere export LC_CTYPE="en_US.UTF-8"?
— Reman,

@Remonn ciao, sai che abbiamo un file di profilo per bash? Metti dentro.
— workplaylifecycle,

@hylepo, sono su un sistema Windows :)
— Reman,

3

Cosa puoi fare se devi apportare una modifica a un file, ma non conosci la codifica del file? Se sai che la codifica è compatibile ASCII e desideri solo esaminare o modificare le parti ASCII, puoi aprire il file con il gestore degli errori surrogateescape:

with open(fname, 'r', encoding="ascii", errors="surrogateescape") as f:
    data = f.read()

0

Ho risolto questo problema semplicemente aggiungendo

df = pd.read_csv(fileName,encoding='latin1')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.