UnicodeDecodeError: кодек «utf8» не может декодировать байт 0x9c

291

У меня есть сервер сокетов, который должен принимать действительные символы UTF-8 от клиентов.

Проблема в том, что некоторые клиенты (в основном хакеры) отправляют через них все неправильные данные.

Я могу легко отличить подлинного клиента, но я записываю в файлы все отправленные данные, чтобы потом проанализировать их.

Иногда я получаю такие символы, œкоторые вызывают UnicodeDecodeErrorошибку.

Я должен быть в состоянии сделать строку UTF-8 с или без этих символов.


Обновить:

В моем конкретном случае служба сокетов была MTA, и поэтому я ожидаю только получения команд ASCII, таких как:

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

Я записывал все это в формате JSON.

Тогда некоторые люди без добрых намерений решили продать все виды мусора.

Вот почему для моего конкретного случая вполне нормально удалить символы, не входящие в ASCII.

transilvlad
источник
1
строка выходит из файла или сокета? Не могли бы вы опубликовать примеры кода того, как строка закодирована и декодирована до того, как она будет отправлена ​​через сокет / обработчик файлов?
devsnd
Я написал или я не написал, что строка приходит через сокет? Я просто читаю строку из сокета и с помощью, чтобы поместить ее в словарь, а затем JSON, чтобы отправить его вместе. Функция JSON не выполнена из-за этих символов.
Transilvlad
Шубхам Шарма

Ответы:

343

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

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

или

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

Примечание. Это приведет к удалению (игнорированию) рассматриваемых символов, возвращая строку без них.

Для меня это идеальный случай, так как я использую его как защиту от ввода не-ASCII, что не разрешено моим приложением.

Альтернативно: используйте метод open из codecsмодуля, чтобы прочитать в файле:

import codecs
with codecs.open(file_name, 'r', encoding='utf-8',
                 errors='ignore') as fdata:
transilvlad
источник
45
Да, хотя это обычно плохая практика / опасная, потому что вы просто потеряете персонажей. Лучше определить или определить кодировку входной строки и сначала декодировать ее в Unicode, а затем кодировать как UTF-8, например:str.decode('cp1252').encode('utf-8')
Бен Хойт
В некоторых случаях да, вы правы, это может вызвать проблемы. В моем случае меня это не волнует, так как они кажутся лишними символами из-за неправильного форматирования и программирования клиентов, подключающихся к моему сокет-серверу.
transilvlad
Это действительно помогает, если содержимое строки на самом деле недопустимо, в моем случае, '\xc0msterdam'которое u'\ufffdmsterdam'заменяется на replace
PvdL
3
если вы оказались здесь из-за проблем с чтением файла, открытие файла в двоичном режиме может помочь: open(file_name, "rb")и затем примените подход Бена из комментариев выше
Кристиан
та же опция применима и к еще большему, например, к «thing.decode () »
Александр Стор,
85

Смена движка с C на Python сделала мой трюк.

Двигатель C:

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

Кодек utf-8 не может декодировать байт 0x92 в позиции 18: недопустимый начальный байт

Двигатель Python:

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

Нет ошибок для меня.

Doğuş
источник
3
это действительно хорошее решение. я не знаю, почему это было понижено.
18:18
1
Отличный ответ. Спасибо. Это сработало для меня. У меня было «?» Внутри символа в форме ромба, который вызывал проблему. С простыми глазами у меня было "" ", которое дюйм. Я сделал 2 вещи, чтобы выяснить. а) df = pd.read_csv ('test.csv', n_rows = 10000). Это отлично работало без двигателя. Поэтому я увеличил n_rows, чтобы выяснить, в какой строке произошла ошибка. б) df = pd.read_csv ('test.csv', engine = 'python'). Это сработало, и я напечатал строку с ошибкой, используя df.iloc [36145], это напечатало мне запись с ошибкой.
Джаганнатха Банерджи
2
это сработало и для меня ... Не уверен, что происходит "под капотом", и если это действительно хорошее / хорошее / правильное решение во всех случаях, но это
помогло
1
Несмотря на то, что работал для меня, я считаю , это так не интуитивно .. Как в мире я бы понять это с кем - то из точки его? Мне любопытно узнать, откуда он взялся ...
Зеленый,
1
Отличное решение! Огромное спасибо.
Печи
62

Этот тип проблем возникает у меня сейчас, когда я перешел на Python 3. Я понятия не имел, что Python 2 просто обрабатывает любые проблемы с кодировкой файлов.

Я нашел это хорошее объяснение различий и того, как найти решение после того, как ничего из вышеперечисленного не помогло мне.

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

Короче говоря, чтобы заставить Python 3 вести себя как можно ближе к использованию Python 2:

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

Тем не менее, прочитайте статью, там не один размер подходит для всех решений.

Джеймс МакКормак
источник
29
>>> '\x9c'.decode('cp1252')
u'\u0153'
>>> print '\x9c'.decode('cp1252')
œ
Игнасио Васкес-Абрамс
источник
16
Я запутался, как вы выбрали cp1252? У меня это сработало, но почему? Я не знаю, и теперь я потерян: /. Не могли бы вы уточнить? Большое спасибо ! :)
Кирилл Н.
4
Не могли бы вы представить опцию, которая работает для всех персонажей? Есть ли способ обнаружить символы, которые нужно декодировать, чтобы можно было реализовать более общий код? Я вижу, что многие люди смотрят на это, и я держу пари, что некоторые отказы не являются желаемым вариантом, как это для меня.
Transilvlad
Как видите, этот вопрос довольно популярен. Думаешь, ты мог бы расширить свой ответ более общим решением?
Transilvlad
13
Нет более универсального решения для «Угадай кодировочную рулетку»
Puppy
5
нашел его с помощью комбинации веб-поиска, удачи и интуиции: cp1252 былused by default in the legacy components of Microsoft Windows in English and some other Western languages
bolov
24

У меня была UnicodeDecodeErrorтакая же проблема, и я решил ее с этой строкой. Не знаю, если это лучший способ, но это сработало для меня.

str = str.decode('unicode_escape').encode('utf-8')
maiky_forrester
источник
14

первый, используя get_encoding_type, чтобы получить тип файла кодирования:

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

во-вторых, открывая файлы с типом:

open(current_file, 'r', encoding = get_encoding_type, errors='ignore')
Иван Ли
источник
1
что произойдет, когда вернется None
Чоп Лабалагун
3

На всякий случай у кого-то такая же проблема. Я использую vim с YouCompleteMe , мне не удалось запустить ycmd с этим сообщением об ошибке, что я и сделал: export LC_CTYPE="en_US.UTF-8"проблема исчезла.

workplaylifecycle
источник
2
Как это связано с этим вопросом?
transilvlad
1
Точно так же, если вы знаете, как работает ваш вопрос. Плагин Ycm представляет собой архитектуру сокетов, связь между клиентом и сервером использует сокет, оба являются модулями Python, не могут декодировать пакеты, если настройка кодирования неверна
workplaylifecycle
У меня та же проблема. Подскажите, пожалуйста, где поставить export LC_CTYPE="en_US.UTF-8"?
Реман
@Remonn привет, ты знаешь, у нас есть файл профиля для bash? Положить внутрь.
workplaylifecycle
@hylepo, я работаю в системе Windows :)
Reman
3

Что вы можете сделать, если вам нужно внести изменения в файл, но вы не знаете кодировку файла? Если вы знаете, что кодировка совместима с ASCII и хотите проверять или изменять только части ASCII, вы можете открыть файл с помощью обработчика ошибок surrogateescape:

with open(fname, 'r', encoding="ascii", errors="surrogateescape") as f:
    data = f.read()
Котхапати Пурандхар Редди
источник
0

Я решил эту проблему, просто добавив

df = pd.read_csv(fileName,encoding='latin1')
Талха Расул
источник