print "\xF0\x9F\x8C\x80"
print u"\U0001F300"
print u"\ud83c\udf00"
我该如何在\x、\u和\U之间进行转换?我无法弄清这些十六进制数是如何相等的。
print "\xF0\x9F\x8C\x80"
print u"\U0001F300"
print u"\ud83c\udf00"
我该如何在\x、\u和\U之间进行转换?我无法弄清这些十六进制数是如何相等的。
>>> "\xF0\x9F\x8C\x80".decode('utf8')
u'\U0001f300'
u"\ud83c\udf00"
是 UTF16 版本(四位unicode转义)。
u"\U0001F300"
是代码点的实际索引。
但是这些数字有什么关系呢? 这是个困难的问题。它由编码定义,没有明显的关系。为了给您一个概念,下面是“手动”将索引为0x1F300的代码点编码成UTF-8的示例:
旋风字符的索引为0x1f300,属于范围0x00010000 - 0x001FFFFF。该范围的模板如下:
11110... 10...... 10...... 10......
你需要用二进制表示填写点的位置。我无法告诉你为什么模板看起来像这样,这只是utf-8的定义。
这里是我们代码点的二进制表示:
>>> u''
u'\U0001f300'
>>> unichr(0x1f300)
u'\U0001f300'
>>> bin(0x1f300)
'0b11111001100000000'
因此,如果我们按以下方式填充字符串模板(由于模板中的插槽比我们的数字中的有效数字多一些,因此需要添加一些前导零),我们将得到以下结果:
11110... 10...... 10...... 10......
11110000 10011111 10001100 10000000
>>> 0b11110000100111111000110010000000
4036988032
>>> hex(4036988032)
'0xf09f8c80'
这里是代码点的UTF8表示方式。
对于UTF16,您的代码点有一个类似的“神奇配方”:从索引中减去0x10000,然后用零填充以获得20位二进制表示。前十位加上0xD800为第一个16位码元,后十位加上0xDC00为第二个16位码元。
>>> bin(0x1f300 - 0x10000)[2:].rjust(20, '0')
'00001111001100000000'
>>> _[:10], _[10:]
('0000111100', '1100000000')
>>> hex(0b0000111100 + 0xd800)
'0xd83c'
>>> hex(0b1100000000 + 0xdc00)
'0xdf00'
b'[11/5/19, 11:38:00 AM] \xe2\x80\xaa+49\xc2\xa0178\xc2\xa03464334\xe2\x80\xac: \xe2\x80\x8eMessages and calls are end-to-end encrypted. No one outside of this chat, not even WhatsApp, can read or listen to them'
,我想要“转义”Unicode字符,但是当我使用.decode('utf-8')
时,结果的字节字符串仍然只有Unicode代码点,而不是实际将它们转换为可打印字符:'[11/5/19, 11:38:00 AM] \u202a+49\xa0178\xa03464334\u202c: \u200eMessages
(截断)。 (1/2) - Raleigh L.你的第一个字符串是一个字节字符串。它打印单个表情符号的事实意味着你的控制台被配置为打印UTF-8编码字符。
你的第二个字符串是一个Unicode字符串,只有一个代码点U+1F300
。 \U
指定下一个8个十六进制数字应该被解释为一个代码点。
第三个字符串利用了Python 2中存储Unicode字符串的一种怪癖。你给出了两个UTF-16实体,它们一起形成了与前一个字符串相同的单个代码点U+1F300
。每个\u
后面跟着4个十六进制数字。单独这些字符不是有效的Unicode,但因为Python 2在内部将其Unicode存储为UTF-16,所以可以正常工作。在Python 3中,这将无效。
u'abcdefghijk'
。可以使用\u
转义序列写入特定的代码点,随后是四个十六进制数字,给出代码点。\U
转义序列类似,但需要8个十六进制数字,而不是4个。In [1]: "\xF0\x9F\x8C\x80".decode('utf-8')
Out[1]: u'\U0001f300'
In [2]: u'\U0001F300'.encode('utf-8')
Out[2]: '\xf0\x9f\x8c\x80'
In [3]: u'\ud83c\udf00'.encode('utf-8')
Out[3]: '\xf0\x9f\x8c\x80'
\uhhhh --> Unicode character with 16-bit hex value
\Uhhhhhhhh --> Unicode character with 32-bit hex value
0b1100100
(二进制,基数为2)0144
(八进制,基数为8)100
(十进制,基数为10)0x64
(十六进制,基数为16)0b1100100 == 0144 == 100 == 0x64
Unicode编码略微复杂,但原理相同。仅仅因为值看起来不同,并不意味着它们代表的值不同。在Python 2中:
u'\ud83c\udf00' == u'\U0001F300' == "\xF0\x9F\x8C\x80".decode("utf-8")
u'\U0001F300' == b"\xF0\x9F\x8C\x80".decode("utf-8")
当需要显式的 b
(字节前缀)时,必须使用。 u
(Unicode前缀)是可选的,因为所有字符串都被认为包含Unicode,并且只有在3.3及更高版本中才允许使用u
。多字节组合字符……呃,它们不是很好看,对吧?
因此,您展示了Unicode CYCLONE代码点的各种编码方式,其他答案展示了一些在代码点之间移动的方法。请参见此处以获取该字符的更多编码。
u'\ud83c\udf00' == u'\U0001F300'
并不是真的。 - wim
u"\U0001F300"==u"\ud83c\udf00"
是Python 2 'narrow' builds的缺陷,通常不是您想要依赖的内容。如果您想使用表情符号,请始终使用\U
形式。 - bobince\xF0\x9F\x8C\x80
等同于ð
。你为什么在代码中写了``呢? - Toothpick Anemoneprint(b"\xF0\x9F\x8C\x80".decode())
。 - wim