2014-10-28 68 views
2

我想用Python编写一个StringIO对象中的数据,然后最终使用psycopg2将这些数据加载到postgres数据库中copy_from()函数。UnicodeDecodeError:'ascii'编解码器无法解码位置47中的字节0x92:序号不在范围内(128)

首先当我这样做时,copy_from()引发错误:ERROR:编码“UTF8”的无效字节序列:0xc92所以我遵循this question

我发现我的Postgres数据库有UTF8编码。

文件/ StringIO对象,我写我的数据转换成显示出其作为下面的编码: setgid的非ISO扩展ASCII英文文本,有很长的线,CRLF行终止

我试图编码每一个我正在写入中间文件/ StringIO对象的字符串转换为UTF8格式。为每个字符串使用.encode(encoding ='UTF-8',errors ='strict'))。

这是我现在得到了错误: 的UnicodeDecodeError:在47位“ASCII”编解码器不能解码字节0x92:有序不在范围内(128)

是什么意思?我如何解决它?

编辑: 我使用Python 2.7 我的一些代码片段:

我从在UTF-8编码为每MySQL工作台数据MySQL数据库读取。 这是写我的数据的几行代码(这是从MySQL数据库获得)中,StringIO对象:

# Populate the table_data variable with rows delimited by \n and columns delimited by \t 
row_num=0 
for row in cursor.fetchall() : 

    # Separate rows in a table by new line delimiter 
    if(row_num!=0): 
     table_data.write("\n") 

    col_num=0 
    for cell in row:  
     # Separate cells in a row by tab delimiter 
     if(col_num!=0): 
      table_data.write("\t") 

     table_data.write(cell.encode(encoding='UTF-8',errors='strict')) 
     col_num = col_num+1 

    row_num = row_num+1 

这是从我的StringIO对象TABLE_DATA写入Postgres数据库的代码:

cursor = db_connection.cursor() 
cursor.copy_from(table_data, <postgres_table_name>) 
+0

请显示您的代码 – 2014-10-28 23:17:13

+0

您使用的是哪种MySQL包装? – abarnert 2014-10-28 23:59:49

+0

此外,不是显示“我的代码的某些部分”,而是创建一个自包含的[最小,完整,可验证的示例](http://stackoverflow.com/help/mcve)并在此处发布。 – abarnert 2014-10-29 00:02:26

回答

6

问题是,您在str对象上调用encode

A str是一个字节字符串,通常表示以某种方式编码的文本,如UTF-8。当你打电话给encode时,它首先必须解码回文本,所以文本可以重新编码。默认情况下,Python通过调用s.decode(sys.getgetdefaultencoding())来实现,而getdefaultencoding()通常返回'ascii'

所以,你说的是UTF-8编码的文本,把它解码就好像它是ASCII码,然后用UTF-8重新编码它。

一般的解决方案是用正确的编码显式调用decode,而不是让Python使用默认值,然后encode的结果。

但当正确的编码已经是你想要的,更容易的解决办法是只跳过.decode('utf-8').encode('utf-8'),只是使用UTF-8 str为UTF-8 str,它已经是了。

,或者,如果你的MySQL包装有一个功能,让你指定的编码,并取回unicodeCHAR/VARCHAR/TEXT列,而不是str值(例如,在MySQLdb中,如果数据库太旧而不能自动检测到,则将use_unicode=True传递给connect调用,或者charset='UTF-8'),只需执行此操作即可。那么你将有unicode对象,你可以打电话给.encode('utf-8')

一般来说,处理Unicode问题的最佳方法是最后一个 - 尽可能早地解码所有内容,使用Unicode进行所有处理,然后尽可能晚地进行编码。但无论如何,你必须保持一致。不要致电str的东西可能是unicode;不要将str文字连接到unicode或将其传递给replace方法;等等。无论你什么时候你混合搭配,Python都会使用默认编码隐式转换为你,这几乎不是你想要的。

作为一个方面说明,这是Python 3.x的Unicode更改所帮助的许多事情之一。首先,str现在是Unicode文本,而不是编码字节。更重要的是,如果的编码字节数为,例如在bytes对象中,则调用encode会给你一个AttributeError,而不是试图以静默方式解码以便它可以重新编码。而且,类似地,试图混合和匹配Unicode和字节会给你一个明显的TypeError,而不是在某些情况下成功的隐式转换,并给出关于其他人未要求的编码或解码的神秘消息。

+0

我尝试在使用use_unicode = True的MYSQL数据库连接中传递charset ='UTF-8'。还意识到源MySQL数据库中的一些表是latin1_swedish_ci,而有些表是utf_8。 我得到一个错误,现在这个样子: db_connection = MySQLdb.connect(主机=主机,用户=用户,passwd文件= passwd文件,DB = DB,字符集= “utf-8”,use_unicode = TRUE) 电池= STR(细胞).replace(“\ r”,“”).replace(“\ n”,“”).replace(“\”“,”“) UnicodeEncodeError:'ascii '编解码器不能在位置47编码字符u':u''':序号不在范围内(128) – user3422637 2014-10-29 20:49:59

+0

@ user3422637:好的,如果你想使用'unicode'对象而不是'str'-这是个好主意 - 那么你不能在它们上面调用'str',因为它会立即尝试将它们编码为默认的字符集,而且你不应该混合和匹配你所做的'unicode'和'str'对象,因为这样做也必须隐式地编码或解码其中一个;使用'replace(u“\ r”,u“”)等等(实际上,'“\ r”'在另一个wa中是坏的如果你有反斜杠,要么逃避它们,要么使用一个原始字符串文字。) – abarnert 2014-10-29 22:27:38

+0

@ user3422637:更一般地说,如果你试图在事物没有真正理解的情况下对事物施加压力,那么你只会得到越来越多的失落。如果你还没有阅读[Unicode HOWTO](https://docs.python.org/2/howto/unicode.html),请阅读。 – abarnert 2014-10-29 22:28:18

相关问题