【发布时间】:2012-04-08 09:43:22
【问题描述】:
在 Python 2 中,Unicode 字符串可能同时包含 unicode 和字节:
a = u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'
我知道这绝对是不应该在自己的代码中编写,但这是我必须处理的字符串。
上面字符串中的字节是 UTF-8 for ек (Unicode \u0435\u043a)。
我的目标是获得一个包含 Unicode 格式的所有内容的 unicode 字符串,即Русский ек (\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u0435\u043a)。
将其编码为 UTF-8 产生
>>> 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'
然后从 UTF-8 解码得到带有字节的初始字符串,这不好:
>>> a.encode('utf-8').decode('utf-8')
u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'
我找到了一个解决问题的方法,但是:
>>> 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'
# Almost there, the bytes are proper now but the former real-unicode characters
# are now escaped with \u's; need to un-escape them.
>>> 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' # Success!
这很好用,但由于使用了eval、repr,然后对 unicode 字符串表示进行了额外的正则表达式,因此看起来很 hacky。有没有更清洁的方法?
【问题讨论】:
-
没有可靠的方法来解决这个问题,因为输入数据首先没有包含足够的信息。
-
输入数据中的所有字节都是UTF-8编码的字符,所以我认为可以安全地假设初始字符串中的每个字节序列都可以安全地从UTF-8解码
-
@NiklasB。是正确的 - UTF-8 编码字节也是有效的 Unicode 代码点,所以没有办法知道什么是可靠的。
-
@EtiennePerot,如果您从 UTF-8 字节序列开始,请将其添加到问题中。您向我们展示的是一个不同的 Unicode 字符串!
-
顺便说一句,“Русский ек”似乎也无效,它可能应该是“Русский язык”(=俄语),所以我想还有更多的问题。
标签: python unicode utf-8 character-encoding