Ошибка кодирования в 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 файла, которые я пытался декодировать, работали нормально. На полпути через третийфайлПитон выплевывает

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
 Mark Tolonen08 окт. 2010 г., 08:03
Когда вы открывали файл в текстовом редакторе, все ли символы отображались правильно? Какая кодировка, по вашему мнению, была в вашем текстовом редакторе?
 rallen07 окт. 2010 г., 20:47
К сожалению нет.
 Daenyth07 окт. 2010 г., 18:57
Можете ли вы спросить источник CSV, как он закодирован?

Ответы на вопрос(3)

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

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

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

Решение Вопроса

"" "... 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, HKSCS big5 код 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'
>>>
 rallen17 окт. 2010 г., 18:16
@John: '\ xf8 \ xf8'.decode (' gb18030 ') действительно работал на меня. Вы спросили, что это за символы, которые gb18030 декодирует, а gbk нет, и IIRC \ xf8 \ xf8 был единственным таким примером. Я не могу проверить примеры до завтра, но я считаю, что "было потеряно, когда был только один такой \ x80 - например, C1 C2 80 22 -> C1 C2, когда я использовал" ignore ", что соответствует вашей" Eureka " ».
 rallen15 окт. 2010 г., 20:38
@John: Из-за данных я не могу поделиться всей строкой, но то, что я назвал символом евро, находится в: \ xcb \\ xbe \\ x80 \\ x80 "." Символ евро ", когда он появляется, находится всегда в том же столбце, который мне не нужен, поэтому я надеялся просто использовать «ignore». К сожалению, поскольку «euro char» находится рядом с кавычками в файле, иногда «ignore» избавляет от обоих Символ евро также заключает в кавычки, что создает проблему для модуля csv для определения столбцов. И «пробел» - это \\ xf8 \\ xf8. Извините за задержку с вами - я только что понял, как получить только байты.
 rallen20 окт. 2010 г., 23:35
@John: Да, спасибо за разъяснения - я неправильно прочитал ранее как \ x81 & \ xfe вместо \ x81 в \ xfe, что привело к проблеме, вызванной (2), поэтому я удалил свой ответ.
 Michael Madsen12 окт. 2010 г., 23:22
Блокнотделает угадайте кодировку вашего файла, но только из очень ограниченного подмножества (системный набор символов или ANSI, UTF-8, UTF-16LE, UTF-16BE). Это источник полу-известного«Буш скрыл факты» ошибка.
 rallen12 окт. 2010 г., 23:43
Я не осознавал, что GBK и GB18030 были так близки, поэтому я отказался от GBK, как только я получил свою первую ошибку в начале декодирования файла. То, что GB18030 декодировал, что GBK не было, было пустым пространством шириной в один символ. К сожалению, мои оригинальные файлы Access содержат это же пространство при открытии. Я думаю, что я просто воспользуюсь опцией «игнорировать» ошибки, так как я обнаружил, что таких файлов в моих файлах было относительно немного, когда я использовал GB18030, и все те, которые я проверял, оказались в столбцах моих данных, которые не иметь значение. Еще раз спасибо.
 John Machin13 окт. 2010 г., 00:34
@rallen: (3) Все ли известные вам проблемы связаны с пробелом и евро? Если нет, то есть вероятность того, что у вас есть данные, созданные в Guandong или HK, на компьютере под управлением китайской Windows (локаль PRC, так что gbk / cp936) с гаджетом MS с болтовым креплением для поддержки HKSCS ... для этого нет кодека. У меня есть несколько сценариев для облегчения изучения файлов, которые «почти» декодируются; если вам нужна / нужна дополнительная помощь, напишите мне по электронной почте (поиск по электронной почте "john machin xlrd" должен найти адрес).
 rallen08 окт. 2010 г., 18:06
Спасибо за предложения. 1.) Он был успешно расшифрован в обоих смыслах. Для первых двух файлов как минимум. В третьем файле это было успешно в том смысле, что то, что было декодировано, было исправлено. Но для линий со знаками евро это бросило ошибку. 2.) Firefox неправильно распознает кодировку. 3.) Я не уверен, что декодирование читается в текстовом редакторе - в блокноте / Notepad ++ это просто говорит ANSI; из того, что я прочитал, это кажется странным / неправильным. 4.) Текст из материкового Китая, не содержит документации и действительно является конфиденциальным.
 John Machin13 окт. 2010 г., 00:33
@rallen: Спасибо за обновление. (1) Что это был за «один пробел шириной в один символ»? Не может быть U + 3000 ИДЕОГРАФИЧЕСКОГО ПРОСТРАНСТВА, которое является первым двухбайтовым символом ('\xA1\xA1') в целомGB* кодировок. Что такое код GB18030 для этого пространства? (2) В конце концов, это может стать настоящей проблемой для ЕВРО: в кодеке Python для GBK aka CP936 есть ошибка; он не обновил его, добавив отображение 0x80 -> U + 20AC EURO SIGN (через 10 лет после его добавления)
 John Machin13 окт. 2010 г., 00:40
@ Майкл Мэдсен: Да, я должен был сказать "не очень хорошо угадывает". Кстати, ANSI означает «системный набор символов» в Windows и, таким образом, является переносным праздником; cp1252 - обычный подозреваемый, но это может быть, например, cp949 (корейский).
 John Machin20 окт. 2010 г., 23:31
@rallen: есть ДВА главных различия между "как 2-ой байт 2-байтовой последовательности, начинающейся с \ x81 до \ xfe" и "предшествующей \ x81 или \ xfe": (1) опускается "\ x81 or \ xfe" все байты в диапазоне от \ x82 до \ xfd включительно (2) вы можете узнать, находитесь ли вы в действительной двухбайтовой последовательности, начиная с известной / предполагаемой допустимой границы символа. Байты в диапазоне \ x81- \ xfe являются действительными начальными байтами И байтами следа в двухбайтовой последовательности. Попробуйте расшифровать \ xcb \ xbe \ x80 \ x22 (\ xbe - это байт следа, \ x80 недопустим) и \ xbe \ x80 \ x22 (\ xbe - это ведущий байт, \ x80 - действительный байт следа).

Ваш ответ на вопрос