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


291

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

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

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

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

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


Обновить:

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

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

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

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

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


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:

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

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


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

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"проблема исчезла.


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()

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.