【问题标题】:How can I check a Python unicode string to see that it *actually* is proper Unicode?如何检查 Python unicode 字符串以查看它*实际上*是正确的 Unicode?
【发布时间】:2010-08-15 12:38:02
【问题描述】:

所以我有这个页面:

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

显然它是一团糟,因为它被正确解码但是当我尝试将它保存在 postgres 中时,我得到:

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

数据库在此之后停止工作,并且在没有回滚的情况下拒绝执行任何操作,这将有点难以发布(长话短说)。有没有办法让我在它到达数据库之前检查这是否会发生? source.encode("utf-8") 工作顺利,所以我不确定发生了什么......

【问题讨论】:

  • 您确定您的连接设置为使用 UTF-8 吗?
  • 是的,添加了 300,000 个其他网页就好了,只是这个失败了……

标签: python postgresql unicode


【解决方案1】:

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]https://www.rfc-editor.org/rfc/rfc3629#section-4

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

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

【讨论】:

  • 没问题。在将 COPY 复制到 postgres 时,我试图或多或少地做你正在做的事情来过滤我的数据。我最终做的只是让它失败并根据错误输出过滤掉各个行。它基于 pgloader 中的复制代码如何工作的一般概念pgfoundry.org/projects/pgloader
  • 不相关:如果你想修复代理对:u'[\ud83d\ude42]'.encode('utf-16', 'surrogatepass').decode('utf-16') = u'[\U0001f642]'
【解决方案2】:

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 是一个str 编码为Utf-8 以外的其他东西,您应该对该编码进行解码,然后将生成的Unicode 对象编码为UTF-8:

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

【讨论】:

  • 对不起,我应该澄清一下。 source 是一个 unicode 对象,它在 Python 中可以很好地编码,当我尝试将它发送到 postgres 时,事情会中断......
【解决方案3】:

你到底在做什么?内容确实可以解码为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 所说的那样检查数据库和数据库连接的设置。

【讨论】:

  • 我正在使用 Django,它可以正确编码所有内容,但是由于某种原因,它决定编码(或编码字符串)不好的是 postgres...我在 Python 中所做的一切都有效,这就是为什么我检测不出来。也许这是一个 postgres 错误?
【解决方案4】:

最后,我选择解决这个问题,捕获错误并使用 Django 的事务管理回滚事务。不过,我很困惑为什么会发生这种情况……

【讨论】:

    【解决方案5】:

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

    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)
    

    【讨论】:

      猜你喜欢
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-26
      • 2018-05-03
      • 2016-12-21
      • 2021-04-15
      • 1970-01-01
      相关资源
      最近更新 更多