Python 3 — строка с шестнадцатеричными значениями \xHH в Unicode

Я пытаюсь преобразовать строку с символами, для которых требуется несколько шестнадцатеричных значений, например:

'Mahou Shoujo Madoka\xe2\x98\x85Magica'

к его представлению в юникоде:

'Mahou Shoujo Madoka★Magica'

Когда я печатаю строку, она пытается оценить каждое шестнадцатеричное значение отдельно, поэтому по умолчанию я получаю следующее:

x = 'Mahou Shoujo Madoka\xe2\x98\x85Magica'
print(x)

Mahou Shoujo MadokaâMagica

поэтому я пробовал некоторые другие ответы StackOverflow, такие как Best способ конвертировать строку в байты в Python 3?:

x = 'Mahou Shoujo Madoka\xe2\x98\x85Magica'
z = x.encode('utf-8')
print('z:', z)
y = z.decode('utf-8')
print('y:', y)

z: b'Mahou Shoujo Madoka\xc3\xa2\xc2\x98\xc2\x85Magica'
y: Mahou Shoujo MadokaâMagica

Python: преобразование Unicode-Hex-String в Unicode:

z = 'Mahou Shoujo Madoka\xe2\x98\x85Magica'
x = binascii.unhexlify(binascii.hexlify(z.encode('utf-8'))).decode('utf-8')
print('x:', x)

x: Mahou Shoujo MadokaâMagica

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

Что я заметил, так это то, что когда я делаю str.encode, кажется, что он добавляет некоторые дополнительные значения в двоичный файл (например, разницу между z и x в первой попытке), и я не совсем уверен, почему.

Поэтому я попытался вручную ввести символы строки в двоичный файл:

x = b'Mahou Shoujo Madoka\xe2\x98\x85Magica'
x.decode('utf-8')

'Mahou Shoujo Madoka★Magica'

и это сработало. Но я не мог найти способ преобразовать строку в двоичный файл буквально, кроме как напечатать его. Где я ошибаюсь?


person user14678939    schedule 14.03.2017    source источник


Ответы (1)


В Python 3 ваша исходная строка является строкой Unicode, но содержит кодовые точки Unicode, которые выглядят как UTF-8, но неправильно декодируются. Починить это:

>>> s = 'Mahou Shoujo Madoka\xe2\x98\x85Magica'
>>> type(s)
<class 'str'>
>>> s.encode('latin1')
b'Mahou Shoujo Madoka\xe2\x98\x85Magica'
>>> s.encode('latin1').decode('utf8')
'Mahou Shoujo Madoka★Magica'

Кодировка latin1 отображает 1:1 на первые 256 кодовых точек в Unicode, поэтому .encode('latin1') переводит кодовые точки непосредственно обратно в байты. Затем вы можете правильно .decode('utf8') байты.

person Mark Tolonen    schedule 14.03.2017
comment
Чтобы присвоить строку переменной, вы также можете сократить вышеприведенное до s = b"\xe2\x98\x85".decode("utf8"). - person Jens; 23.09.2017
comment
@Jens, ты мог бы сократить это до s='★', но вопрос был не в этом. - person Mark Tolonen; 23.09.2017