UTF-8 Ошибка кодирования, нужна помощь в преобразовании текста - PullRequest
2 голосов
/ 23 февраля 2010

Я работал над статистической системой перевода для Гаити (code.google.com/p/ccmts), которая использует бэкэнд C ++ (http://www.statmt.org/moses/?n=Development.GetStarted), а Python управляет движком / бэкэндом C ++.

Я передал строку Python UTF-8 в C ++ std::string, выполнил некоторую обработку, получил результат обратно в Python, и вот строка (при печати из C ++ в терминал Linux):

mwen bezwen à £ ¨ d medikal

  1. Какая это кодировка? Это строка с двойным кодированием?
  2. Как мне "исправить это", чтобы оно могло быть отображено?
  3. Это напечатано таким образом, потому что мне не хватает шрифта или что-то?

Библиотека Python chardet сообщает:

{'confidence': 0.93812499999999999, 'encoding': 'utf-8'}

но, Python, когда я запускаю декодирование строки / юникода / кодеков, я получаю старое:

UnicodeDecodeError: кодек «ascii» не может декодировать байт 0xc3 в позиции 30: порядковый номер не в диапазоне (128)

О, и Python выводит ту же самую строку в стандартный вывод.

A repr() call печатает следующее: 'mwen bezwen \ xc3 \ xa3 \ xc2 \ xa8 d medikal'

Ответы [ 3 ]

3 голосов
/ 24 февраля 2010

Похоже на случай мусора в мусор. Вот несколько подсказок о том, как увидеть, что у вас есть в ваших данных. repr() и unicodedata.name() ваши друзья.

>>> s = ' mwen bezwen \xc3\xa3 \xc2\xa8 d medikal '
>>> print repr(s.decode('utf8'))
u' mwen bezwen \xe3 \xa8 d medikal '
>>> import unicodedata
>>> unicodedata.name(u'\xe3')
'LATIN SMALL LETTER A WITH TILDE'
>>> unicodedata.name(u'\xa8')
'DIAERESIS'
>>>

Обновление:

Если (как предполагает А. Н. Другой) вы позволяете пакету выбирать язык вывода случайным образом, и вы подозреваете, что его выбор, например, Корейский (а) скажите нам (б) попытаться декодировать вывод с помощью кодека, относящегося к этому языку .... здесь есть не только корейский, но также два по-китайски, японский и русский:

>>> s = ' mwen bezwen \xc3\xa3 \xc2\xa8 d medikal '
>>> for enc in 'euc-kr big5 gb2312 shift-jis euc-jp cp1251 koi8-r'.split():
    print enc, s.decode(enc)


euc-kr  mwen bezwen 찾 짢 d medikal 
big5  mwen bezwen 瓊 穡 d medikal 
gb2312  mwen bezwen 茫 篓 d medikal 
shift-jis  mwen bezwen テ」 ツィ d medikal 
euc-jp  mwen bezwen 達 即 d medikal 
cp1251  mwen bezwen ГЈ ВЁ d medikal 
koi8-r  mwen bezwen цё б╗ d medikal 
>>> 

На самом деле, нет ничего особенно правдоподобного, особенно koi8-r. Дополнительные предложения: Изучите документацию пакета, с которым вы взаимодействуете (URL, пожалуйста!) ... что он говорит о кодировании? Между какими двумя языками вы пробуете это? Имеет ли смысл mwen bezwen в ожидаемом языке вывода? Попробуйте намного больший образец текста - chardet все еще указывает UTF-8? Имеет ли смысл какой-либо из больших выводов в ожидаемом языке вывода? Попробуйте перевести английский на другой язык, который использует только ASCII - вы получаете значимый вывод ASCII? Вы хотите разглашать свой код Python и код интерфейса Swig?

обновление 2 Интересен информационный поток: "приложение для обработки строк" -> "система перевода на статистический язык" -> "система машинного перевода (opensource / freesoftware) для помощи на Гаити ( crisiscommons.org) "

Пожалуйста, попробуйте заменить слова «неизвестно» фактами следующего содержания:

Input language: English (guess)
Output language: Haitian Creole
Operating system: linux
Python version: unknown
C++ package name: unknown
C++ package URL: unknown
C++ package output encoding: unknown

Test 1 input: unknown
Test 1 expected output: unknown
Test 1 actual output (utf8): ' mwen bezwen \xc3\xa3 \xc2\xa8 d medikal '
[Are all of those internal spaces really in the string?]

Test 2 input: 'I need medical aid.'
Test 2 expected output (utf8): 'Mwen bezwen \xc3\xa8d medikal.'
Test 2 actual output (utf8): unknown

Тест 2, полученный от Google Translate (альфа) * ​​1021 * и Microsoft Translate (бета) :
Mwen bezwen èd medikal.
Третье слово - ЛАТИНСКОЕ МАЛЕНЬКОЕ ПИСЬМО Е с ГРЕВОМ (U + 00E8), за которым следует «d».

Обновление 3

Вы сказали "" "input: utf8 (возможно, я думаю, что в некоторых моих файлах может быть неправильно закодированный текст)" ""

Предполагая (вы никогда не указывали это явно), что все ваши файлы должны быть закодированы в UTF-8:

В zip-файле выровненного корпуса en-fr-ht есть несколько файлов, которые вылетают при попытке декодировать их как UTF-8.

Диагностика того, почему это происходит:

chardet бесполезен (в данном случае); он бродит долго и возвращается с предположением ISO-8859-2 (Восточная Европа или Латинская 2) с уровнем достоверности от 80 до 90%.

Следующий шаг: выбрал каталог ht-en (ht использует меньше акцентированных символов, чем fr, поэтому легче увидеть, что происходит).

Ожидание: e-grave является наиболее часто встречающимся не-ASCII символом в предположительно хорошем тексте ht (веб-сайт, файлы CMU) ... примерно в 3 раза больше, чем следующий, o-grave. Третий по частоте теряется в шуме.

Получил количество байтов не ascii в файле hten.txt. Топ 5:

8a 99164
95 27682
c3 8210
a8 6004
b2 2159

Последние три строки объясняются

e-grave is c3 a8 in UTF-8
o-grave is c3 b2 in UTF-8
2159 + 6004 approx == 8210
6004 approx == 3 * 2159

Первые 2 строки объясняются

e-grave is 8a in old Western Europe DOS encodings like cp850!!
o-grave is 95 in old Western Europe DOS encodings like cp850!!
99164 approx == 3 * 27682

Пояснения, которые включают латиницу 1 или cp1252, не содержат воды (8a - контрольный символ в латинице 1; 8a - S-caron в cp1252).

Проверка содержимого показывает, что файл представляет собой конгломерат нескольких исходных файлов, некоторые из которых имеют формат UTF-8, по крайней мере, один cp850 (или аналогичный). Виновником оказывается Библия !!!

Смесь кодировок объясняет, почему Чарде боролся.

Предложения:

(1) Реализовать проверку кодировки во всех входных файлах. Убедитесь, что они конвертированы в UTF-8 сразу, как при пограничном контроле.

(2) Реализовать скрипт для проверки декодируемости UTF-8 перед выпуском.

(3) Орфография текста Библии (на первый взгляд) отличается от орфографии веб-сайтов (еще много апострофов). Возможно, вы захотите обсудить с вашими креольскими экспертами, искажается ли ваш корпус из-за другой орфографии ... есть также вопрос слов; Вы ожидаете получить много пресного хлеба, вретище и пепла? Обратите внимание, что материал cp850 составляет около 90% конгломерата; может быть, с какой-то Библией все в порядке, но 90% кажется чрезмерным.

(4) Почему Моисей не жалуется на ввод не-UTF-8? Возможности: (1) он работает с необработанными байтами, т.е. он не конвертируется в Unicode (2) он пытается конвертировать в Unicode, но молча игнорирует ошибку: - (

1 голос
/ 24 февраля 2010

Редактировать: не обращайте внимания на тот мусор, который я отправил раньше; это было неправильно.

Как и предполагали другие, это даст вам правильный объект Unicode в Python, если предположить, что это будет utf-8:

>>> ' mwen bezwen \xc3\xa3 \xc2\xa8 d medikal '.decode('utf-8')
u' mwen bezwen \xe3 \xa8 d medikal '
>>> print _
 mwen bezwen ã ¨ d medikal

Это действительно похоже на случай, когда ваша библиотека дает вам мусор, будь то мусор, когда в него или нет.

1 голос
/ 23 февраля 2010

Похоже, ваша кодировка по умолчанию - ASCII.

Вы можете явно конвертировать строки в юникоде:

print u"Hellö, Wörld".encode("utf-8")

Или, если вы хотите изменить это глобально в своем скрипте, замените sys.stdout оболочкой, которая кодирует его как utf-8:

import sys, codecs
sys.stdout = codecs.EncodedFile(sys.stdout, "utf-8")
print u"Hellö, Wörld!"

Кроме того, вы можете изменить кодировку по умолчанию раз и навсегда (для всего сайта) с помощью sys.setdefaultencoding , но это можно сделать только в sitecustomize.py . Однако я бы не стал этого делать - это может показаться удобным, так как оно влияет на все сценарии python в вашей системе и может иметь непреднамеренные побочные эффекты.

...