unicode Python字符串中的字节

2024-09-29 19:16:40 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python2中,Unicode字符串可以同时包含Unicode和字节:

a = u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'

我知道这绝对不是一个人应该在自己的代码中编写的东西,但这是一个字符串,我必须处理它。

上面字符串中的字节是ек(Unicode\u0435\u043a)的UTF-8。

我的目标是得到一个包含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!

它工作得很好,但由于使用了evalrepr,然后对unicode字符串表示进行了额外的正则表达式处理,因此看起来非常粗糙。有更干净的方法吗?


Tags: 字符串字节unicodereprxd0xbau0438u0435
3条回答

问题是字符串实际上不是用特定编码编码的。示例字符串:

a = u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \xd0\xb5\xd0\xba'

将python的unicode字符串的内部表示与utf-8编码文本混合。如果我们只考虑“特殊”字符:

>>> orig = u'\u0435\u043a'
>>> bytes = u'\xd0\xb5\xd0\xba'
>>> print orig
ек
>>> print bytes
ек

但是你说,bytesutf-8编码的:

>>> print bytes.encode('utf-8')
ек
>>> print bytes.encode('utf-8').decode('utf-8')
ек

错了!但是呢:

>>> bytes = '\xd0\xb5\xd0\xba'
>>> print bytes
ек
>>> print bytes.decode('utf-8')
ек

欢呼。

所以。这对我意味着什么?这意味着你(可能)解决了错误的问题。你应该问我们/试图弄清楚为什么你的字符串以这种形式开始,以及如何避免它/在你把它们都弄混之前修复它。

(针对上面的注释):此代码转换所有看起来像utf8的代码,并保留其他代码点:

a = u'\u0420\u0443\u0441 utf:\xd0\xb5\xd0\xba bytes:bl\xe4\xe4'

def convert(s):
    try:
        return s.group(0).encode('latin1').decode('utf8')
    except:
        return s.group(0)

import re
a = re.sub(r'[\x80-\xFF]+', convert, a)
print a.encode('utf8')   

结果:

Рус utf:ек bytes:blää  

In Python 2, Unicode strings may contain both unicode and bytes:

不,他们可能不会。它们包含Unicode字符。

在原始字符串中,\xd0不是UTF-8编码的一部分。它是带有代码点208的Unicode字符。u'\xd0'==u'\u00d0'。恰好Python 2中Unicode字符串的repr更喜欢用\x转义来表示字符(即代码点<;256)。

无法查看字符串并指出\xd0字节应该是某个UTF-8编码字符的一部分,或者它实际上代表该Unicode字符本身。

但是,如果假设您始终可以将这些值解释为已编码的值,则可以尝试编写一些内容,依次分析每个字符(使用ord转换为代码点整数),将字符<;256解码为UTF-8,并按原样传递字符>;=256。

相关问题 更多 >

    热门问题