为什么字符串和列表在UNICODE(utf-8)中有所不同?怎么能' - '制作错误?

时间:2016-02-04 11:46:31

标签: python unicode

>>> final=[]
>>> for a in range(65535):
        final.append([a,chr(a)])


>>> file=open('1.txt','w',encoding='utf-8')
>>> file.write(str(final))
960881
>>> file.close()
>>> final=''
>>> for a in range(65535):
        final+='%d -------- %s'%(a,chr(a))


>>> file=open('2.txt','w',encoding='utf-8')
>>> file.write(final)
Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    file.write(final)
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 873642: surrogates not allowed

如您所见,保存了1.txt。为什么保存第二个文件&#39;(字符串)会出错?

3 个答案:

答案 0 :(得分:1)

From Wikibooks

  

Unicode和ISO / IEC 10646不会将实际字符分配给D800-DFFF范围内的任何代码点 - 这些代码点仅在代理项对中使用时具有意义。因此,代理对中的单个代码点不代表字符,除非在代理项对中使用,否则无效

所以我说chr(0xd800)已经无效了,我猜Python只是因为速度原因没有检查它。但UTF-8编码器确实检查并抱怨。

它适用于第一个文件的原因是将字符串包装在列表中并使用该列表上的str导致repr - 字符串:

>>> str( chr(0xd800) )
'\ud800'
>>> str([chr(0xd800)])
"['\\ud800']"

请注意列表版本中的双反斜杠。它不是一个“无效字符”\ud800,而是六个有效字符\ud80和{{1} }}。那些可以编码。

答案 1 :(得分:0)

代码点boost::iostreams::file_descriptor_source fds(fd, boost::iostreams::close_handle); U+D800保留给surrogate pairs,并且已经在错误消息中看到了

  

UnicodeEncodeError:&#39; utf-8&#39;编解码器不能对字符&#39; \ ud800&#39;进行编码。在位置873642:代理人不被允许

您无法在该范围内书写字符。它仅用于UTF-16编码代码点outside the BMP(即&gt; 65535)。

请注意,Unicode 是16位字符集,因此高达65535 就足够了。要打印所有Unicode字符,除了代理范围外,您需要一直打印到U+​10FFFF。相反,使用UTF-32也更容易

答案 2 :(得分:-1)

我不知道如何将UTF-16传递给UTF-8的好方法,但如果您要求100%,您可能会应用此方法来读取文件准确的代表:

f = open(filename, encoding='utf-8', errors='replace')