如何检查Python unicode字符串以确定它* *实际上是*正确的Unicode?

时间:2010-08-15 12:38:02

标签: python postgresql unicode

所以我有这个页面:

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

显然它是各种各样的混乱,因为它被正确解码但是当我尝试将它保存在postgres中时我得到:

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

数据库在此之后吵了起来并拒绝做任何事情而没有回滚,这将有点难以发布(长篇故事)。有没有办法让我检查一下它是否会在它到达数据库之前发生? source.encode(“utf-8”)顺利运行,所以我不确定发生了什么......

5 个答案:

答案 0 :(得分:9)

python 2.x中有一个 bug ,它只是固定的python 3.x.实际上,这个bug甚至出现在OS X的iconv中(但不是glibc)。

以下是发生的事情:

Python 2.x无法识别UTF8代理对[1]无效(这是您的字符序列)

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

但是由于这个错误他们没有修复,它没有捕获代理对。

在python 2.x中尝试,然后在3.x:

中尝试
b'\xed\xbd\xbf'.decode('utf8')

它会在后者中引发错误(正确)。他们也没有在2.x分支中修复它。有关详细信息,请参阅[2]和[3]

[1] http://tools.ietf.org/html/rfc3629#section-4

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

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

答案 1 :(得分: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'))

如果sourcestr编码为Utf-8以外的其他内容,则应解码该编码,然后将生成的Unicode对象编码为UTF-8:

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

答案 2 :(得分: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所说,检查数据库和数据库连接的设置。

答案 3 :(得分:0)

最后,我选择了解决这个问题,捕获错误并使用Django的事务管理回滚事务。尽管如此......我为什么会发生这件事我感到很困惑。

答案 4 :(得分:0)

为了解决我与django / postgres的类似问题,我现在做这样的事情

class SafeTextField(models.TextField)
    def get_prep_value(self, value):
        encoded = base64.encodestring(value).strip()
        return super(SafeTextField, self).get_prep_value(encoded)
    def to_python(self, value):
        decoded = base64.decodestring(value)
        return super(SafeTextField, self).to_python(decoded)