Напишите разные шестнадцатеричные значения в Python2 и Python3

В настоящее время я переношу скрипт Python2 на Python3 и имею проблемы с этой строкой:

print('\xfe')

Когда я запускаю его с Python2 python test.py > test.out, файл состоит из шестнадцатеричных значений FE 0A, как и ожидалось.

Но когда я запускаю его с Python3 python3 test.py > test.out, файл состоит из шестнадцатеричных значений C3 BE 0A.

Что здесь не так? Как я могу получить желаемый результат FE 0A с помощью Python3.


person Jakube    schedule 14.08.2015    source источник
comment
К вашему сведению, эта последняя запись представляет собой то же значение текстового символа, но в UTF8. Это может дать вам подсказку.   -  person Jongware    schedule 14.08.2015


Ответы (3)


Последовательность байтов C3 BE представляет собой кодированное UTF-8 представление символа U+. 00FE.

Python 2 обрабатывает строки как последовательность байтов, а не символов. Итак, '\xfe' — это объект str, содержащий один байт.

В Python 3 строки представляют собой последовательности символов (Unicode). Таким образом, код '\xfe' представляет собой строку, содержащую один символ. Когда вы печатаете строку, она должна быть закодирована в байты. Поскольку ваша среда выбрала кодировку по умолчанию UTF-8, она была закодирована соответствующим образом.

Как это решить, зависит от ваших данных. Это байты или символы? Если байты, то измените код, чтобы сообщить интерпретатору: print(b'\xfe'). Если это символы, но вы хотели другую кодировку, то закодируйте строку соответствующим образом: print( '\xfe'.encode('latin1') ).

person dsh    schedule 14.08.2015
comment
Вероятно, мне следует в ближайшее время хорошенько взглянуть на Unicode. Но ваши два решения не работают для меня. Я хочу видеть (при вызове python3 test.py >test.out) шестнадцатеричное значение FE в test.out. - person Jakube; 14.08.2015
comment
Нет, с новой строкой все в порядке. Но я хочу, чтобы файл содержал только два байта (FE 0A), а не три байта (CE BE 0A). - person Jakube; 14.08.2015
comment
На самом деле, вы не сможете сделать это с print(). print() применяет repr() к объекту, поскольку это не строка, затем кодирует результирующую строку и записывает ее. - person dsh; 14.08.2015
comment
Вы действительно очень скоро захотите понимать символы и байты: это одно из основных фундаментальных отличий Python 3. Python 2 очень небрежно обрабатывал строки, часто сбивая людей с толку относительно того, обрабатываются ли они байтами или символами. Все объекты str в Python 3 содержат символы Unicode, а bytes — это отдельный тип данных. - person dsh; 14.08.2015
comment
@ user38034: (1) для печати текста всегда используйте Unicode в Python. Не кодируйте жестко кодировку символов, используемую текущей средой в вашем скрипте (2), для печати двоичных данных, таких как данные изображения, сжатые данные (gzip), зашифрованные данные, см. Как записать байты в файл в Python 3, не зная кодировки? - person jfs; 15.08.2015

print '\xfe' Код Python 2 примерно эквивалентен этому коду Python 3:

sys.stdout.buffer.write(b'\xfe' + os.linesep.encode())

в то время как print('\xfe') код Python 3 примерно эквивалентен этому коду Python 3:

sys.stdout.buffer.write((u'\xfe' + os.linesep).encode(sys.stdout.encoding))

В первом случае Python печатает байты. Во втором случае он печатает Unicode, и результат зависит от вашей среды (локали).

>>> u'\xfe'.encode('utf-8')
b'\xc3\xbe'

Для печати текста всегда используйте Unicode в Python. Не задавайте жестко кодировку символов, используемую текущей средой в вашем скрипте.

Чтобы распечатать двоичные данные, такие как данные изображения, сжатые данные (gzip), зашифрованные данные, см. Как записать байты в файл в Python 3 без зная кодировку?

person jfs    schedule 15.08.2015

print(argument) преобразует аргумент с помощью str() (если необходимо), а затем вызывает file.write(string). file является необязательным аргументом print(), и по умолчанию он равен sys.stdout. Это означает, что вы должны быть в состоянии сделать то же самое с sys.stdout.write(str(argument) + '\n'). Итак, результат зависит от используемой кодировки, которую вы можете получить от sys.stdout.encoding. Если вы передаете еще один аргумент file, то объект файла должен быть открыт для записи в режиме text, и, возможно, может быть применена другая кодировка.

person pepr    schedule 14.08.2015