UnicodeDecodeError: el códec 'utf8' no puede decodificar el byte 0x9c

289

Tengo un servidor de socket que se supone que recibe caracteres válidos UTF-8 de los clientes.

El problema es que algunos clientes (principalmente piratas informáticos) envían todo el tipo de datos incorrectos sobre él.

Puedo distinguir fácilmente al cliente genuino, pero estoy ingresando a los archivos todos los datos enviados para poder analizarlos más tarde.

A veces obtengo caracteres como este œque causan el UnicodeDecodeErrorerror.

Necesito poder hacer la cadena UTF-8 con o sin esos caracteres.


Actualizar:

Para mi caso particular, el servicio de socket era un MTA y, por lo tanto, solo espero recibir comandos ASCII como:

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

Estaba registrando todo esto en JSON.

Luego, algunas personas sin buenas intenciones decidieron vender todo tipo de basura.

Es por eso que para mi caso específico está perfectamente bien quitar los caracteres no ASCII.

transilvlad
fuente
1
¿La cadena sale de un archivo o un socket? ¿podría publicar ejemplos de código de cómo se codifica la cadena y se decodifica antes de enviarla a través del socket / controlador de archivos?
devsnd
¿Escribí o no escribí que la cadena viene por el zócalo? Simplemente leí la cadena del zócalo y la puse en un diccionario y luego JSON para enviarla. La función JSON falló debido a esos caracteres.
transilvlad
¿podría por favor poner sus datos de muestra del problema
Shubham Sharma

Respuestas:

343

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

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

o

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

Nota: Esto eliminará (ignorará) los caracteres en cuestión devolviendo la cadena sin ellos.

Para mí, este es el caso ideal, ya que lo estoy usando como protección contra la entrada no ASCII que mi aplicación no permite.

Alternativamente: utilice el método abierto del codecsmódulo para leer en el archivo:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:
transilvlad
fuente
45
Sí, aunque esto suele ser una mala práctica / peligroso, porque solo perderás personajes. Es mejor determinar o detectar la codificación de la cadena de entrada y decodificarla primero en unicode, luego codificar como UTF-8, por ejemplo:str.decode('cp1252').encode('utf-8')
Ben Hoyt
En algunos casos, sí, tiene razón, puede causar problemas. En mi caso, no me importan, ya que parecen ser caracteres adicionales que se originan por el mal formato y la programación de los clientes que se conectan a mi servidor de socket.
transilvlad
Esto realmente ayuda si el contenido de la cadena no es realmente válido, en mi caso, '\xc0msterdam'que se convierte en u'\ufffdmsterdam'reemplazar
PvdL
3
si terminó aquí porque tiene problemas para leer un archivo, abrir el archivo en modo binario podría ayudar: open(file_name, "rb")y luego aplique el enfoque de Ben de los comentarios anteriores
kristian
la misma opción se aplica a aún más, por ejemplo, a "something.decode ()"
Alexander Stohr
83

Cambiar el motor de C a Python hizo el truco para mí.

El motor es C:

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

El códec 'utf-8' no puede decodificar el byte 0x92 en la posición 18: byte de inicio no válido

El motor es Python:

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

No hay errores para mi.

Doğuş
fuente
3
Esa es realmente una buena solución. No sé por qué fue rechazado.
ℕʘʘḆḽḘ
Esto podría no ser una buena idea si tiene un csvarchivo enorme . Podría provocar un OutOfMemoryerror o un reinicio automático del kernel de su computadora portátil. Debe configurar el encodingen este caso.
LucasBr
1
Excelente respuesta Gracias. Esto funcionó para mí. Tenía "?" Dentro de un personaje en forma de diamante que estaba causando el problema. Con los ojos claros tenía "" ", que es una pulgada. Hice 2 cosas para resolver. a) df = pd.read_csv ('test.csv', n_rows = 10000). Esto funcionó perfectamente sin el motor. Así que incrementé las n_rows para descubrir qué fila tenía un error. b) df = pd.read_csv ('test.csv', motor = 'python'). Esto funcionó e imprimí la fila con errores usando df.iloc [36145], esto me imprimió el registro con errores.
Jagannath Banerjee
1
esto también funcionó para mí ... No estoy seguro de lo que está sucediendo 'bajo el capó' y si esta es realmente una buena / buena / adecuada solución en todos los casos, pero fue el truco para mí;)
Chrisvdberge
1
Gran solución! Muchas gracias.
Pechi
62

Este tipo de problema surge para mí ahora que me mudé a Python 3. No tenía idea de que Python 2 simplemente estaba resolviendo cualquier problema con la codificación de archivos.

Encontré esta buena explicación de las diferencias y cómo encontrar una solución después de que nada de lo anterior funcionó para mí.

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

En resumen, para hacer que Python 3 se comporte de la manera más similar posible al uso de Python 2:

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

Sin embargo, lea el artículo, no hay una solución única para todos.

James McCormac
fuente
29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ
Ignacio Vazquez-Abrams
fuente
16
Estoy confundido, ¿cómo elegiste cp1252? A mí me funcionó, pero ¿por qué? No lo sé y ahora estoy perdido: /. ¿Podrías dar más detalles? Muchas gracias ! :)
Cyril N.
44
¿Podría presentar una opción que funcione para todos los personajes? ¿Hay alguna forma de detectar los caracteres que deben decodificarse para que se pueda implementar un código más genérico? Veo que muchas personas están viendo esto y apuesto a que algunos descartes no son la opción deseada como lo es para mí.
transilvlad
Como puede ver, esta pregunta tiene bastante popularidad. ¿Crees que podrías ampliar tu respuesta con una solución más genérica?
transilvlad
13
No hay más solución genérica para "Adivina la ruleta de codificación"
Puppy
55
Lo encontré usando una combinación de búsqueda web, suerte e intuición: cp1252 fueused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov
24

Tuve el mismo problema UnicodeDecodeErrory lo resolví con esta línea. No sé si es la mejor manera, pero funcionó para mí.

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

el primero, usando get_encoding_type para obtener el tipo de archivo de codificación:

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']

el segundo, abriendo los archivos con el tipo:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')
Ivan Lee
fuente
1
qué sucede cuando regresa Ninguno
Chop Labalagun
3

Por si acaso alguien tiene el mismo problema. Estoy usando vim con YouCompleteMe , no pude iniciar ycmd con este mensaje de error, lo que hice fue: export LC_CTYPE="en_US.UTF-8"el problema desapareció.

workplaylifecycle
fuente
2
¿Cómo se relaciona esto con esta pregunta?
transilvlad
1
Exactamente lo mismo, si sabes cómo trabajas. El complemento Ycm es arquitectura de socket, la comunicación entre el cliente y el servidor está usando socket, ambos son módulos de python, no pueden decodificar los paquetes si la configuración de codificación es incorrecta
workplaylifecycle
Tengo el mismo problema. ¿Me puede decir dónde ponerlo export LC_CTYPE="en_US.UTF-8"?
Reman
@Remonn hola, ¿sabes que tenemos un archivo de perfil para bash? Poner dentro.
workplaylifecycle
@hylepo, estoy en un sistema de Windows :)
Reman
3

¿Qué puede hacer si necesita hacer un cambio en un archivo, pero no conoce la codificación del archivo? Si sabe que la codificación es compatible con ASCII y solo desea examinar o modificar las partes ASCII, puede abrir el archivo con el controlador de error de subrogación de escape:

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

He resuelto este problema simplemente agregando

df = pd.read_csv(fileName,encoding='latin1')
Talha Rasool
fuente