2014-04-24 2 views
1

Я создаю виртуальную машину в RPython, используя PyPy. Проблема в том, что когда я пытался добавить поддержку unicode, я обнаружил необычную проблему. Я буду использовать букву «á» в своих примерах.Ошибка юникода Python

# The char in the example is á 
print len(char) 

OUTPUT: 
2 

Я понимаю, как буква «А» занимает два байта, следовательно, длину 2. Но проблема в том, когда я использую этот пример ниже я столкнулся с этой проблемой.

# In this example instr = "á" (including the quotes) 
for char in instr: 
    print hex(int(ord(char))) 

OUTPUT: 
0x22 
0xc3 
0xa1 
0x22 

Как вы можете найти 4 номера. Для 0x22 для кавычек, но между кавычками есть только 1 буква, но есть два числа. Мой вопрос, некоторые машины я тестировал этот сценарий по производимому этот выход:

OUTPUT: 
0x22 
0xe1 
0x22 

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

+0

unrelated: для преобразования байта в шестнадцатеричную строку: 'print (binascii.hexlify (instr))' – jfs

+0

Ваш код в вопросе предназначен для Python 2 (судя по выражению 'print' и содержимому' '' á "'') – jfs

ответ

0

Проблема в том, что вы используете bytestrings для работы с текстовыми данными. Вместо этого вы должны использовать Unicode.

Это означает, что вам необходимо знать кодировку символов ваших входных данных - There Ain't No Such Thing As Plain Text.

Если вы знаете кодировку, то легко конвертировать байтовой строки в Unicode т.д .:

unicode_text = bytestring.decode(encoding) 

Он должен решить ваш первоначальный вопрос.

Есть также Unicode normalization forms, например.:

import unicodedata 

norm_text = unicodedata.normalize('NFC', unicode_text) 

Если я не изменить кодировку в программе, как я могу вывода символов Юникода, например?

Вы могли бы означать, что у вас есть последовательность байтов, например, '\xc3\xa1' (два байта), которые могут быть интерпретированы как текст, используя некоторый характер кодирования, например, он находится в UTF-8 U+00E1 Unicode codepoint. Это может быть что-то другое в кодировке другого символа. Прочтите приведенную выше ссылку The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).

Если случайно ваш терминал не использует такую ​​же кодировку символов, как данные в вашем входном файле; вы должны иметь возможность конвертировать из одной кодировки символов в другую. В противном случае выход будет поврежден, например, вместо á вы можете получить ├б на экране.

В обычном Python вы можете использовать методы bytes.decode, unicode.encode (или непосредственно модуль codecs). Я не знаю, возможно ли это в RPython.

+0

Есть ли способ декодировать строку без метода декодирования? В RPython я не могу использовать метод .decode. – user3566150

+0

@ user3566150: Я не знаю, поддерживает ли RPython кодировки вообще. Откуда берутся данные? Почему он использует разные кодировки символов на разных машинах? – jfs

+0

Данные поступают из текстового файла. RPython использует ascii по умолчанию, поскольку он основан на Python 2. Вы можете использовать функцию unicode(), если у нее есть только один параметр, и вы можете сказать u «Some string» для создания строки unicode, но вы можете использовать «Something». декодировать ("utf8"). В RPython есть несколько функций для обмена сообщениями с юникодом, но я обнаружил проблему и в них. Например, они могут преобразовать escape-код unicode \ uE1, но они не могут выполнять каждый символ в Юникоде, он говорит об ошибке Unicode Decode при попытке декодирования прошлых \ ​​uF5. – user3566150

1

Программа не дают один и тот же вход на двух машинах:

In [154]: '\xe1'.decode('cp1252').encode('utf_8') == '\xc3\xa1' 
Out[154]: True 

При вводе á в консоли, вы можете увидеть глиф á, но консоль переводит, что в байтах. Конкретные байты, которые он переводит, зависят от кодировки, используемой консолью. На машине Windows это может быть cp1252, тогда как на машине Unix это может быть utf-8.

Таким образом, вы можете видеть вход как тот же, но консоль (и, следовательно, программа) получает разные входные данные.

Если ваша программа должна была декодировать байты с соответствующей кодировкой, а затем работать с unicode, то обе программы будут работать одинаково после этой точки. Если вы получаете байты от sys.stdin, то sys.stdin.encoding будет кодировать Python, который использует консоль.

+0

Как изменится вход? – user3566150

1

У вас есть этот вопрос с тегом «Python-3.x» - возможно ли, что на некоторых машинах работает Python 2.x, а в других работает Python 3.x?

Символ á на самом деле U+00E1, поэтому в системе Python 3.x я ожидаю увидеть ваш второй выход. Поскольку строки Unicode в Python3 по умолчанию, len(char) будет 3 (включая кавычки).

В Python 2.x тот же символ в строке будет содержать два байта и (в зависимости от вашего метода ввода) будет представлен в UTF-8 как \xc3\xa1. В этой системе len(char) будет 4, и вы увидите свой первый выход.

Смежные вопросы