En Python 2, les chaînes Unicode peuvent contenir à la fois des caractères Unicode et des octets :
a = u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'
Je comprends que ceci est absolument quelque chose qu'on ne devrait pas écrire dans son propre code, mais c'est une chaîne avec laquelle je dois travailler.
Les octets dans la chaîne ci-dessus sont en UTF-8 pour (Unicode \u0435\u043a
).
Mon objectif est d'obtenir une chaîne Unicode contenant tout en Unicode, c'est-à-dire (\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u0435\u043a
).
L'encoder en UTF-8 donne
>>> a.encode('utf-8')
'\xd0\xa0\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9 \xc3\x90\xc2\xb5\xc3\x90\xc2\xba'
Qui, décodé depuis UTF-8, donne la chaîne initiale avec des octets dedans, ce qui n'est pas bon :
>>> a.encode('utf-8').decode('utf-8')
u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'
J'ai trouvé un moyen bricolé pour résoudre le problème, cependant :
>>> repr(a)
"u'\\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439 \\xd0\\xb5\\xd0\\xba'"
>>> eval(repr(a)[1:])
'\\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439 \xd0\xb5\xd0\xba'
>>> s = eval(repr(a)[1:]).decode('utf8')
>>> s
u'\\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439 \u0435\u043a'
# Presque là, les octets sont corrects maintenant mais les anciens caractères réels Unicode
# sont maintenant échappés avec des \u ; il faut donc les déséchapper.
>>> import re
>>> re.sub(u'\\\\u([a-f\\d]+)', lambda x : unichr(int(x.group(1), 16)), s)
u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u0435\u043a' # Succès !
Cela fonctionne bien mais semble très bricolé en raison de son utilisation de eval
, repr
, et ensuite de la regex supplémentaire de la représentation de la chaîne Unicode. Y a-t-il un moyen plus propre ?