Я создаю простую игру, предназначенную для запроса пользователю греческого перевода английского слова. Например:
cow: # here, the gamer would answer with *η αγελάδα* in order to score one point.
Я использую вспомогательную функцию для чтения и декодирования из txt файла. Я делаю это, используя следующий код в указанной функции:
# The variable filename refers to my helper function 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"
Примечание. После проверки ответа на ответ, я узнал, что preended oject (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
В ответ на вопрос, похожий на мой, пользователь TΖΩΤΖΙΟΥ сказал, что он импортирует модуль unicodedata и вызывает метод нормализации (который я сделал в коде выше), но я подозреваю, что это может и не понадобиться. К сожалению, этот шаг программы не вызывает беспокойства, поскольку у меня есть проблема, декодирующая ввод пользователя. Чтобы продемонстрировать, когда я печатаю каноническое строковое представление user_reply и соответствующего ключа в моем словаре [используя built- in 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 'η αγελάδα'
η αγελάδα
>>>
ВВЕРХ: Мне пришлось менять шрифт консоли по умолчанию на Lucida Console. Это решило мое несоответствие.
Для части вашего вопроса используйте:
words_text = codecs.open(filename, 'r', 'utf-8-sig')
и он обработает обработку byte- order- метки \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
>>>
Стандартная оболочка 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:]
Таким образом вы отбрасываете его, если он там.
sys.stdin.encoding
иsys.stdout.encoding
? Если вы можете ввести греческую строку в командной строке, она должна быть декодируемой в Unicode и кодируемой для печати.