Latin1字符值与utf8中的显示不同

时间:2013-12-11 01:43:45

标签: python unicode encoding utf-8 latin1

FOR PYTHON 2.7(我在3中使用了编码并且现在都很困惑...会喜欢一些建议如何在python 3中复制这个测试....)

对于欧元字符(€),我查看了其utf8十六进制代码点使用this tool的内容。它说它是0x20AC。

对于Latin1(再次使用Python2 2.7),我使用decode来获取其Hex代码点:

>>import unicodedata
>>p='€'
## notably x80 seems to correspond to [Windows CP1252 according to the link][2]
>>p.decode('latin-1') 
>>u'\x80'

然后我用这两个打印语句,这就是我得到的:

for utf8:

>>> print unichr(0x20AC).encode('utf-8')
€

for latin-1:

>>> print unichr(0x80).encode('latin-1')
€

发生了什么事?为什么编码为utf-8返回'â,'?另外......似乎Latin1十六进制代码点与他们的utf8对应物不同(我有一个相信不同的同事 - 说拉丁语1在这方面就像ASCII一样)。但是不同代码点的存在似乎对我提出了另外的建议......然而,python 2.7正在阅读Windows CP1252 'x80'的原因对我来说是一个真正的谜......这是python中latin-1的标准2.7 ??

1 个答案:

答案 0 :(得分:4)

你在这里遇到了一些严重的误解。如果您还没有阅读Python 2Python 3的Unicode HOWTO,那么您应该从那里开始。

首先,UTF-8是Unicode到8位字节的编码。没有UTF-8代码点0x20AC这样的东西。有一个 Unicode 代码点U + 20AC,但在UTF-8中,这是三个字节:0xE20x820xAC


这解释了你在这里的困惑:

  

为什么编码为utf-8返回'â,'?

没有。它返回了字节串'\xE2\x82\xAC'。然后,print将其输出到您的控制台。你的控制台大概是在CP-1252中,因此它将这些字节解释为CP-1252,它们为你提供了€


同时,当你写这个:

p='€'

控制台没有提供Python Unicode,它在CP-1252中提供Python字节,Python只存储为字节。欧元符号的CP-1252为\x80。所以,这与输入相同:

p='\x80'

但是在Latin-1中,\x80不是欧元符号,它是一个不可见的控制字符,相当于Unicode U + 0080。因此,当您致电p.decode('latin-1')时,您会收到u'\x80'。这正是你所看到的。


你无法在Python 3中重现这一点的原因是在Python 3中,str和普通字符串文字是Unicode字符串,而不是字节字符串。所以,当你写这个:

p='€'

...控制台为Python提供了一些字节,然后Python会自动将其为控制台(CP-1252)猜测的字符集解码为Unicode。所以,这相当于写这个:

p='\u20ac'

......或者这个:

p=b'\x80'.decode(sys.stdin.encoding)

另外,你一直说“十六进制代码点”是指各种不同的东西,没有任何意义。

代码点是Unicode概念。 Python中的unicode字符串是一系列代码点。 str bytes 的序列,而不是代码点。十六进制只是表示数字的一种方式 - 十六进制数20AC0x20AC与十进制数8364相同,十六进制数0x80为与十进制数128相同。

这个字节序列本身没有任何固有的含义;它需要与编码结合才能产生意义。根据编码,某些代码点可能根本无法表示,而其他代码点可能需要2个或更多字节来表示。


最后:

  

另外......似乎Latin1十六进制代码点可以与他们的utf8对应点不同(我有一个相信不同的同事 - 说拉丁语1在这方面就像ASCII一样。)

Latin-1是ASCII的超集。 Unicode也是Latin-1的可打印子集的超集;一些直到U + FF的Unicode字符(以及直到U + 7F的所有可打印字符)都以UTF-8编码为具有与代码点相同值的字节,但不是全部。 CP-1252是Latin-1的可打印子集的不同超集。由于 在ASCII或Latin-1中没有欧元符号,因此CP-1252和UTF-8以不同方式表示它是完全合理的。