Ошибка кодирования в Python с китайскими иероглифами

Я новичок, испытывающий затруднения при декодировании нескольких десятков CSV-файлов с номерами + (упрощенные) китайские иероглифы в UTF-8 в Python 2.7.

Я не знаю кодировку входных файлов, поэтому я испробовал все возможные кодировки, которые мне известны - GB18030, UTF-7, UTF-8, UTF-16 и UTF-32 (LE & BE). Кроме того, для хорошей оценки, GBK и GB3212, хотя они должны быть подмножеством GB18030. Все UTF останавливаются, когда добираются до первых китайских иероглифов. Другие кодировки останавливаются где-то в первой строке, кроме GB18030. Я думал, что это будет решением, потому что он прочитал первые несколько файлов и декодировал их хорошо. Часть моего кода, читая построчно:

line = line.decode("GB18030")

Первые 2 файла, которые я пытался декодировать, работали нормально. Посередине третьего файла Python выплевывает

UnicodeDecodeError: 'gb18030' codec can't decode bytes in position 168-169: illegal multibyte sequence

В этом файле около 5 таких ошибок на миллион строк.

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

Изменить: я использовал chardet что дало GB2312 в качестве кодировки с доверием.99 для всех файлов. Я попытался использовать GB2312 для декодирования, который дал:

UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 108-109: illegal multibyte sequence

3 ответа

Решение

""" ... GB18030. Я думал, что это будет решением, потому что он читает первые несколько файлов и прекрасно их декодирует.""" Пожалуйста, объясните, что вы имеете в виду. Для меня есть ДВА критерия для успешного декодирования: во-первых, что raw_bytes.decode('some_encoding') не потерпел неудачу, во-вторых, что результирующий юникод при отображении имеет смысл на определенном языке. Каждый файл во вселенной пройдет первый тест при декодировании с latin1 ака iso_8859_1, Многие файлы на восточноазиатских языках проходят первый тест с gb18030потому что в основном часто используемые символы на китайском, японском и корейском языках кодируются с использованием одинаковых блоков двухбайтовых последовательностей. Сколько из второго теста вы сделали?

Не пытайтесь смотреть на данные в IDE или текстовом редакторе. Посмотрите на это в веб-браузере; они обычно делают лучшую работу по обнаружению кодировок.

Откуда ты знаешь, что это европейский персонаж? Глядя на экран текстового редактора, который декодирует необработанные байты, используя какую кодировку? cp1252?

Откуда вы знаете, что он содержит китайские иероглифы? Вы уверены, что это не японец? Корейский язык? Откуда ты это взял?

Китайские файлы, созданные в Гонконге, Тайване, может быть, в Макао и других местах за пределами материка big5 или же big5_hkscs кодирование - попробуйте это.

В любом случае, примите совет Марка и укажите chardet на него; chardet обычно делает достаточно хорошую работу по обнаружению используемой кодировки, если файл достаточно велик и правильно закодирован на китайском / японском / корейском - однако, если кто-то вручную редактировал файл в текстовом редакторе, используя однобайтовую кодировку, несколько нелегально символы могут привести к тому, что кодировка, используемая для остальных 99,9% символов, не будет обнаружена.

Вы можете сделать print repr(line) скажем 5 строк из файла и отредактируйте вывод в свой вопрос.

Если файл не является конфиденциальным, вы можете сделать его доступным для загрузки.

Был ли файл создан в Windows? Как вы читаете это в Python? (показать код)

Обновление после OP комментариев:

Блокнот и т. Д. Не пытайтесь угадать кодировку; "ANSI" является значением по умолчанию. Вы должны сказать ему, что делать. То, что вы называете символом евро, - это необработанный байт "\x80", декодированный вашим редактором с использованием кодировки по умолчанию для вашей среды - обычно подозрительным является "cp1252". Не используйте такой редактор для редактирования вашего файла.

Ранее вы говорили о "первых нескольких ошибках". Теперь вы говорите, что у вас всего 5 ошибок. Пожалуйста, объясни.

Если файл действительно почти правильный gb18030, вы должны иметь возможность декодировать файл построчно, и когда вы получите такую ​​ошибку, перехватите ее, распечатайте сообщение об ошибке, извлеките смещения байтов из сообщения, напечатайте repr(two_bad_bytes) и продолжай. Мне очень интересно, какой из двух байтов \x80 появляется. Если он вообще не появляется, "символ евро" не является частью вашей проблемы. Обратите внимание, что \x80 может корректно отображаться в файле gb18030, но только как 2-й байт двухбайтовой последовательности, начинающейся с \x81 в \xfe,

Это хорошая идея, чтобы узнать, в чем ваша проблема, прежде чем пытаться ее исправить. Попытка исправить это, используя блокнот и т. Д. В режиме "ANSI", не является хорошей идеей.

Вы очень стеснялись, когда решили, что результаты декодирования gb18030 имеют смысл. В частности, я бы внимательно изучил строки, где gbk не работает, но gb18030 "работает" - там должно быть несколько очень редких китайских символов, или, может быть, некоторые некитайские символы не ASCII...

Вот предложение для лучшего способа осмотра повреждения: декодируйте каждый файл с raw_bytes.decode(encoding, 'replace') и запишите результат (закодированный в utf8) в другой файл. Подсчитайте ошибки по result.count(u'\ufffd'), Просмотрите выходной файл, используя то, что вы использовали, чтобы решить, имеет ли смысл декодирование gb18030. Символ U + FFFD должен отображаться в виде белого вопросительного знака внутри черного ромба.

Если вы решите, что некодируемые кусочки могут быть отброшены, самый простой способ raw_bytes.decode(encoding, 'ignore')

Обновить после получения дополнительной информации

Всех тех \\ сбивают с толку. Похоже, что "получение байтов" включает в себя repr(repr(bytes)) вместо просто repr(bytes)... в интерактивном режиме, либо bytes (вы получите отчет repr ()), или print repr(bytes) (который не получит неявное repr ())

Пустое пространство: я предполагаю, что вы имеете в виду, что '\xf8\xf8'.decode('gb18030') это то, что вы интерпретируете как некое пространство во всю ширину, и что интерпретация выполняется путем визуального осмотра с использованием некоторого неназванного программного обеспечения для просмотра. Это верно?

На самом деле, '\xf8\xf8'.decode('gb18030') -> u'\e28b', U+E28B находится в Юникоде PUA (зона личного пользования). "Пробел", по-видимому, означает, что программное обеспечение для просмотра не имеет смысла без символа U+E28B в используемом шрифте.

Возможно, источник файлов намеренно использует PUA для символов, которых нет в стандарте gb18030, или для аннотации, или для передачи псевдосекретной информации. Если это так, вам нужно будет прибегнуть к расшифровке бубна, ответвлению недавнего российского исследования, о котором сообщалось здесь.

Альтернатива: теория cp939-HKSCS. Согласно правительству HK, код big57 HKSCS FE57 когда-то был сопоставлен с U+E28B, но теперь сопоставлен с U+28804.

"Евро": Вы сказали "" "Из-за данных я не могу поделиться всей строкой, но то, что я называл символом евро, находится в: \xcb\xbe\x80\x80" [Я предполагаю, что \ был опущен с самого начала, а " буквально]. "Символ евро", когда он появляется, всегда находится в том же столбце, который мне не нужен, поэтому я надеялся просто использовать "игнорировать". К сожалению, так как "euro char" находится рядом с кавычками в файле, иногда "ignore" избавляет как от кавычек, так и кавычек [as], что создает проблему для модуля csv при определении столбцов "" "

Было бы очень полезно, если бы вы могли показать образцы того, где эти \x80 байты появляются по отношению к кавычкам и китайским символам - сохраняйте их читаемыми, просто показывая гекс, и скрывайте свои конфиденциальные данные, например, используя C1 C2 для представления "двух байтов, которые, я уверен, представляют китайский символ". Например:

C1 C2 C1 C2 cb be 80 80 22 # `\x22` is the quote character

Пожалуйста, приведите примеры (1), где "не потеряно при замене" или "игнорировать" (2), когда цитата потеряна. В вашем единственном примере на сегодняшний день "не потеряно":

>>> '\xcb\xbe\x80\x80\x22'.decode('gb18030', 'ignore')
u'\u53f8"'

И предложение отправить вам некоторый код отладки (см. Пример выходных данных ниже) все еще открыто.

>>> import decode_debug as de
>>> def logger(s):
...    sys.stderr.write('*** ' + s + '\n')
...
>>> import sys
>>> de.decode_debug('\xcb\xbe\x80\x80\x22', 'gb18030', 'replace', logger)
*** input[2:5] ('\x80\x80"') doesn't start with a plausible code sequence
*** input[3:5] ('\x80"') doesn't start with a plausible code sequence
u'\u53f8\ufffd\ufffd"'
>>> de.decode_debug('\xcb\xbe\x80\x80\x22', 'gb18030', 'ignore', logger)
*** input[2:5] ('\x80\x80"') doesn't start with a plausible code sequence
*** input[3:5] ('\x80"') doesn't start with a plausible code sequence
u'\u53f8"'
>>>

Эврика: - Вероятная причина иногда потерять символ кавычки -

Кажется, есть ошибка в gb18030 Декодер заменяет / игнорирует механизм: \x80 не является допустимым старшим байтом gb18030; когда это обнаружено, декодер должен попытаться выполнить повторную синхронизацию с байтом NEXT. Однако, похоже, игнорирует как \x80 И следующий байт:

>>> '\x80abcd'.decode('gb18030', 'replace')
u'\ufffdbcd' # the 'a' is lost
>>> de.decode_debug('\x80abcd', 'gb18030', 'replace', logger)
*** input[0:4] ('\x80abc') doesn't start with a plausible code sequence
u'\ufffdabcd'
>>> '\x80\x80abcd'.decode('gb18030', 'replace')
u'\ufffdabcd' # the second '\x80' is lost
>>> de.decode_debug('\x80\x80abcd', 'gb18030', 'replace', logger)
*** input[0:4] ('\x80\x80ab') doesn't start with a plausible code sequence
*** input[1:5] ('\x80abc') doesn't start with a plausible code sequence
u'\ufffd\ufffdabcd'
>>>

Вы можете попробовать Chardet.

Попробуй это:

codecs.open(file, encoding='gb18030', errors='replace')

Не забудьте параметр errorsВы также можете установить "игнорировать".

Другие вопросы по тегам