Как мне решить проблемы с декодированием и печатью греческих символов с использованием Python? - PullRequest
1 голос
/ 27 мая 2011

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

cow: # here, the gamer would answer with *η αγελάδα* in order to score one point.

Я использую вспомогательную функцию для чтения и декодирования из текстового файла. Я делаю это, используя следующий код в указанной функции:

# The variable filename refers to my helper function's sole parameter, it takes the 
# above mentioned txt file as an argument.
words_text = codecs.open(filename, 'r', 'utf-8')

Эта вспомогательная функция затем читает каждую строку. Линии напоминают что-то вроде этого:

# In stack data, when I debug, it reads as u"\η αγελάδα - cow\r\n".
u"\u03b7 \u03b1\u03b3\u03b5\u03bb\u03ac\u03b4\u03b1 - cow\r\n"

Однако первая строка файла при чтении имеет нежелательный префикс, ueff -:

# u"\ufeffη αγελάδα - cow\r\n"
u"\ufeff\u03b7 \u03b1\u03b3\u03b5\u03bb\u03ac\u03b4\u03b1 - cow\r\n"

Примечание. Изучив ответ Марка, я обнаружил, что предварительно добавленный объект (ueff) является сигнатурой спецификации (используется для отличия UTF-8 от других кодировок).

Это небольшая проблема, и я не уверен, как ее убрать самым аккуратным образом. В любом случае, моя вспомогательная функция затем создает и возвращает новый словарь, который выглядит примерно так:

{u'\u03b7 \u03b1\u03b3\u03b5\u03bb\u03ac\u03b4\u03b1': 'cow'}

Затем в своей основной функции я использую следующее для хранения ввода пользователя:

# This is the code for the prompt I noted at the beginning.
# The variable gr_en_dict is the dictionary noted right above.
for key in gr_en_dict:
    user_reply = raw_input('%s: ' % (gr_en_dict[key])).decode(sys.stdout.encoding)

Затем я сравниваю значение ввода пользователя с соответствующим ключом в словаре:

# I imported unicodedata as ud.
if ud.normalize('NFC', user_reply) == ud.normalize('NFC', key):
        score += 1

В ответ на вопрос, похожий на мой, пользователь ΤΖΩΤΖΙΟΥ сказал импортировать модуль unicodedata и вызвать метод нормализации (что я и сделал в приведенном выше коде), но я подозреваю, что в этом нет необходимости. К сожалению, этот шаг программы не имеет значения только потому, что у меня есть проблема с декодированием ввода пользователя. Чтобы продемонстрировать, когда я печатаю каноническое строковое представление user_reply и соответствующего ключа в моем словаре [используя встроенную функцию repr ()], я получаю следующий результат:

ввод пользователя (user_reply):

u'? \u03b1?\u03b5??\u03b4\u03b1'

Если я печатаю ввод пользователя без функции repr (), это выглядит так:

? α?ε??δα

ключ в моем словаре:

u'\u03b7 \u03b1\u03b3\u03b5\u03bb\u03ac\u03b4\u03b1'

Если я печатаю его без repr (), я получаю ошибку:

UnicodeEncodeError: 'charmap' codec can't encode character u'\u03b7' in position 0: character maps to <undefined>

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

Итак, что именно мне нужно сделать, чтобы декодировать введенные пользователем данные и правильно отобразить все греческие символы?

При использовании моей родной кодовой страницы:

C:\>chcp
Active code page: 437

C:\>\python25\python
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.stdout.encoding
'cp437'
>>> print '? α?ε??δα'
? α?ε??δα
>>>

При использовании греческой кодовой страницы: (как ни странно, она отображается правильно только тогда, когда я сначала копирую ее в буфер обмена, а затем вставляю в приложение с типом слова. Я бы разместил изображение того, что он на самом деле печатает, в консоли по умолчанию, но Для этого мне не хватает репутации.)

C:\>chcp 869
Active code page: 869

C:\>\python25\python
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.stdout.encoding
'cp869'
>>> print ' η αγελάδα'
 η αγελάδα
>>> print 'η αγελάδα'
η αγελάδα
>>>

UP: Мне пришлось изменить шрифт консоли по умолчанию на Lucida Console. Это решило мое расхождение.

Ответы [ 2 ]

3 голосов
/ 27 мая 2011

Для части вашего вопроса используйте:

words_text = codecs.open(filename, 'r', 'utf-8-sig')

, и он будет обрабатывать обработку метки порядка байтов \ ufeff.

Технически, это:

user_reply = raw_input('%s: ' % (gr_en_dict[key])).decode(sys.stdout.encoding)

должно быть:

user_reply = raw_input('%s: ' % (gr_en_dict[key])).decode(sys.stdin.encoding)

, но на практике они должны иметь одинаковую кодировку.

Я считаю, что проблема заключается в том, что кодировка в консоли по умолчанию не поддерживает все греческие символы.Когда я перехожу на греческую кодовую страницу, все начинает работать лучше.Обратите внимание, что я могу вставить правильные символы в оператор print ниже, но cp437 фактически не поддерживает все символы, поэтому при печати неподдерживаемые символы заменяются знаком вопроса:

C:\>chcp
Active code page: 437

C:\>python
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.stdout.encoding
'cp437'
>>> print 'η αγελάδα - cow'
? α?ε??δα - cow

ЕслиЯ переключаюсь на греческую кодовую страницу (869 или 1253), она работает:

C:\>chcp 869
Active code page: 869

C:\>python
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.stdout.encoding
'cp869'
>>> print 'η αγελάδα - cow'
η αγελάδα - cow
>>>
1 голос
/ 27 мая 2011

Стандартная оболочка Windows имеет проблемы с расширенными символами.Я бы предложил использовать что-то вроде Windows PowerShell.

Для символа '\ ufeff', который является меткой порядка байтов, вы можете выполнить следующую проверку после чтения в файле:

words_text = codecs.open(filename, 'r', 'utf-8')
words_text_lines = words_text.readlines()

if words_text_lines and words_text_lines[0][0]==unicode(codecs.BOM_UTF8, 'utf8'):
    words_text_lines[0] = words_text_lines[0][1:]

Таким образом, вы отбрасываете его, если он там есть.

...