psycopg拒绝Python的unicode字符串

时间:2016-11-14 19:17:44

标签: python postgresql unicode psycopg2

我收到了来自野外的unicode字符串,导致我们的某些psycopg2语句失败。

我已将问题缩小为SSCE:

import psycopg2
conn = psycopg2.connect(...)
cur = conn.cursor()
x = u'\ud837'
cur.execute("SELECT %s", (x,))
print cur.fetchone()

运行此命令会出现以下异常:

Traceback (most recent call last):
  File ".../run.py", line 65, in <module>
    cur.execute("SELECT %s AS test", (x,))
psycopg2.DataError: invalid byte sequence for encoding "UTF8": 0xed 0xa0 0xb7

基于一些评论,很明显这个特定字符是代理对的一半,使其独立生活无效。

具体来说,我正在寻找一种机制来检测字符串何时在Python 2中包含不完整的代理项对。

我发现一种导致异常的方法是尝试x.encode('utf16').decode('utf16'),但是,由于我并不完全理解相关的风险,所以我会在这里担心。

编辑:将SSCE字符串缩减为导致问题的单个字符,根据评论添加信息。

2 个答案:

答案 0 :(得分:2)

要检测字符串是无效的utf-8,只需在try/except中执行编码之前将其编码为psycopg2

至于导致问题的原因,字符串中间有一个utf-16编码的特定字符:\U000d8a85。所以并不是Postgres不认为utf-8,实际上并非如此。

答案 1 :(得分:2)

字符串formsurrogate pair的唯一成员组成,两个物理字符按顺序出现以形成逻辑字符。因此,它没有定义Unicode代码点 - 相反,它是UTF-16编码的实现细节,它使用它将完整的代码点范围打包成16位代码单元。 Python 3正确拒绝在任何字节编码中编码单独代理的尝试,包括UTF- *变体。

该字符串可能源自内部使用UTF-16的系统(例如使用16位u'\ud837'构建的Java,C#,Windows或Python 2),这些系统可以简单地缩短字符串而不需要处理代理。

this answer获取正则表达式,应该可以使用以下代码有效地检测这些字符串:

Py_UNICODE