如何检查Python的unicode字符串是否是真正的Unicode?

7 投票
5 回答
4586 浏览
提问于 2025-04-16 02:48

我有一个网页:

http://hub.iis.sinica.edu.tw/cytoHubba/

看起来这个网页有点问题,虽然它能正常解码,但当我尝试把它保存到PostgreSQL数据库时,我遇到了:

DatabaseError: invalid byte sequence for encoding "UTF8": 0xedbdbf

数据库在那之后就不再响应了,什么操作都不愿意执行,除非我先回滚,这有点麻烦(长话短说)。有没有办法让我在数据到达数据库之前检查一下,看看会不会发生这种情况?使用source.encode("utf-8")是没问题的,所以我不太明白到底发生了什么……

5 个回答

0

你到底在做什么呢?内容确实可以正常解码为 utf-8 格式:

>>> import urllib
>>> webcontent = urllib.urlopen("http://hub.iis.sinica.edu.tw/cytoHubba/").read()
>>> unicodecontent = webcontent.decode("utf-8")
>>> type(webcontent)
<type 'str'>
>>> type(unicodecontent)
<type 'unicode'>
>>> type(unicodecontent.encode("utf-8"))
<type 'str'>

不过,你得搞清楚 Unicode 字符串和 utf-8 编码字符串之间的区别。你需要发送到数据库的是 unicodecontent.encode("utf-8")(这和 webcontent 是一样的,但你解码是为了确认你的源数据里没有无效的字节序列)。

我建议你像 WoLpH 说的那样,检查一下数据库和数据库连接的设置。

1

在Python中,unicode对象是一串Unicode代码点,按照定义它就是标准的Unicode。而Python中的str字符串则是一串字节,这些字节可能是用某种编码(比如UTF-8、Latin-1、Big5等)编码的Unicode字符。

这里第一个问题是,sourceunicode对象还是str字符串。source.encode("utf-8")能正常工作,只说明你可以把source转换成UTF-8编码的字符串,但你在把它传给数据库函数之前,真的有这样做吗?数据库似乎希望输入是UTF-8编码的,但它抱怨说source.decode("utf-8")的效果不对。

如果sourceunicode对象,你应该在把它传给数据库之前先将其编码为UTF-8:

source = u'abc'
call_db(source.encode('utf-8'))

如果source是用其他编码(不是UTF-8)编码的str,你应该先解码成Unicode对象,然后再将这个Unicode对象编码为UTF-8:

source = 'abc'
call_db(source.decode('Big5').encode('utf-8'))
9

在python 2.x中有一个bug,这个问题在python 3.x中才被修复。实际上,这个bug甚至出现在OS X的iconv中(但在glibc中没有)。

事情是这样的:

Python 2.x不把UTF8替代字符对[1]当作无效的(而你的字符序列就是这样的)。

其实只需要这样就可以了:

foo.decode('utf8').encode('utf8')

但是由于这个他们不打算修复的bug,它无法识别替代字符对。

你可以在python 2.x和3.x中试试这个:

b'\xed\xbd\xbf'.decode('utf8')

在后者中会抛出一个错误(这是正确的)。他们也不会在2.x版本中修复这个问题。想了解更多信息可以查看[2]和[3]

[1] https://www.rfc-editor.org/rfc/rfc3629#section-4

[2] http://bugs.python.org/issue9133

[3] http://bugs.python.org/issue8271#msg102209

撰写回答