在Pg中与psycopg2一起存储的字符显示为代码点而不是字符

时间:2013-12-23 21:30:34

标签: python unicode character-encoding postgresql-9.1 psycopg2

我似乎无法在Postgres中正确存储unicode字符。它们显示为代码表示,例如例如<C3><A5>而不是å

我的数据库是使用UTF-8作为编码创建的。我试过用psycopg2存储unicode字符串,如下所示:

field = myUnicodeString.encoding('utf-8')
cursor.execute("INSERT INTO mytable (column1) VALUES (%s)", (field))

field = myUnicodeString
cursor.execute("INSERT INTO mytable (column1) VALUES (%s)", (field))

但两个替代品都存储不正确的字符。我是否也需要为表格设置字符集,或问题是什么?

更新1:

我发现我甚至无法在终端中键入非ascii字符 - 比如å,ä和ö。我在Ubuntu 12.04服务器上。这可能与服务器本身的语言设置有关吗?

更新2

我现在能够在SSH会话期间在终端中键入非ascii字符。我更改了区域设置并重新启动了服务器。此外,我能够在我的UTF-8数据库中手动存储非ascii字符(在psql中:INSERT INTO table (column) VALUES ('ö'))。 char在psql中正确显示。

当我SELECT convert_to(column, 'utf-8') FROM table在表中手动插入行时,char ö在psql中显示为\xc383c2b6

当我在Python中print repr('ö')时,我得到'\xc3\xb6'。我真的想了解如何调试这个,但我不确定该寻找什么。

1 个答案:

答案 0 :(得分:2)

目前尚不清楚您是否错误地确认了存储字符 。也不清楚问题是在PostgreSQL中使用它们,还是在Python之前使用它们。

在这种情况下,“å”是unicode代码点U + 00E5,在utf-16 BE中编码为0x00E5或在utf-8中编码为0xc3 0xa5。这符合你所看到的 - 一个utf-8字节序列表示“å” - 所以我怀疑你的终端配置错误,无法显示它,或者试图把它解释为latin-1而没有生成的错位文本字体中的正确字符:

>>> print u'å'.encode("utf-8").decode("latin-1")
Ã¥

所以它显示了代码点。

您的Python代码无意义无效:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'encoding'

我认为你的意思是“编码”。无论如何都没必要这样做; Python psycopg2很高兴直接使用unicode字符串对象:

>>> conn = psycopg2.connect("dbname=regress")
>>> curs = conn.cursor()
>>> curs.execute("SELECT %s", (u'áéíóú',));
>>> print curs.fetchone()[0]
áéíóú

对于编码问题,您需要逐步跟踪事项,以确定文本编码被错误处理的位置。

没有足够的信息来回答这样的问题。我真正能提供的只是一般建议。在每一步中,确认您尊重输入的编码,并确保一步的输出采用相同的编码,下一步期望作为输入。

首先,您需要确保您的unicode字符串在Python中是正确的。 print repr(mystring)对此有用,可以查看字符串数据。然后你应该在将它们传递给psycopg2时停止显式编码;让psycopg2处理它。

下一步是使用psql在数据库中检查它们。即使它们无法在终端上正确显示,您也可以使用convert_to函数检查它们是否在数据库中,该函数将数据库字段或字符串文字作为输入,并以所需的编码输出字节序列。所以,例如:

SELECT convert_to(column1, 'utf-8') FROM mytable;

并确保返回的十六进制字节序列与您发送的文本的utf-8编码应该匹配。

继续此过程。在每一步中,检查字符串字节以确保它们匹配应该是什么,直到找到错误处理文本的阶段。

我向你保证,PostgreSQL和psycopg2都不会错误地存储Unicode字符。在这种情况下,它可能是一个简单的问题,因为您的终端设置错误,或者可能是文本处理路径中的某些内容使用了错误的输入编码,因此您将某些内容编码为utf-8,然后将其解码为拉丁语 - 1(例如)。