PostgreSQL数据库的Python编码问题

时间:2016-11-22 17:44:21

标签: python postgresql qgis

我正在开发一个程序,我希望将从csv文件读取的地址与postgres数据库进行比较。 (它是QGis的插件) 只要我在没有自己的参数的情况下发送查询,我就可以成功建立连接并从数据库中读取数据。

所以我做的是: 我读了一个csv文件并将其存储在一个列表中。 然后我选择一个输出文件。 接下来,我单击一个按钮,单击该按钮,应将csv文件中的条目与数据库中的条目进行比较。 如果来自csv文件的条目(邮政编码,城镇,地址)在数据库中具有完全相同的属性,我将其写入“成功匹配”列表,如果一个不匹配,我将其写入列表“错误列表”

当我用自己的参数执行语句时,我的问题就出现了。 我收到的Sql错误消息说:

  

编码UTF8的字节序列无效:0xdf 0x65

我认为,错误发生在我从csv文件填充的第一个列表中。我的地址有特殊字符,如öäüß......

以下是使用的代码:

This Method writes the succesfully matched addresses to a file, the failed ones to a lineEdit

def write_output_file(self):
    compare_input_with_database()
    try:
        with open(self.outputfile, 'wb') as csvfile:
            writer = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
            for row in geocoded_list:
                writer.writerow(row)
        if len(error_list) > 0:
            self.writefailedaddresses()
            raiseInformation("Es konnten nicht alle Adressen geocodiert werden!")
        else:
            raiseInformation("Adressen erfolgreich geocodiert!")
    except csv.Error:
        raiseException("Fehler beim schreiben der Datei")



This method, compares a row entry from the list/csvfile to the database.


def compare_input_with_database():
dbcursor = database_connection.open_connection()
for row in addressList:
    entry = str(row[0])
    addresssplit = entry.split(';')
    try:
        resultset = database_connection.select_specific_address(dbcursor, int(addresssplit[0]), addresssplit[1], addresssplit[2])
        geocoded_list.append(resultset)
    except psycopg2.DatabaseError, e:
        raiseException(e)
        error_list.append(addresssplit)
database_connection.close_connection()

def select_specific_address(cursor, plz, town, address):
cursor.execute("SELECT plz,ort,strasse,breitengrad,laengengrad from addresses where plz=%s AND ort=%s AND strasse=%s", (plz, town, address))
resultset = cursor.fetchone()
return resultset



This Method reads a csv file and populates it in a list

def loadFileToList(addressfile, dlg):
del addressList[:]
if os.path.exists(addressfile):
    if file_is_empty(addressfile):
        raiseException("Ungueltige Quelldatei! Quelldatei ist leer!")
        return -1
    else:
        with open(addressfile, 'rb') as csvfile:
            filereader = csv.reader(csvfile, delimiter=';')
            for row in filereader:
                addressList.append(row)
        return addressList
else:
    raiseException("Pfad der Quelldatei nicht gefunden!")
    return -1

谢谢!

编辑: 当我显示包含特殊字符的地址时,它显示为“Hauptstra \ xdfe”而不是“Hauptstraße” 抱歉,我很难接受编码,这是unicode吗? 这是否意味着,它会像这样发送到数据库,并且我需要以不同的方式对其进行编码?

编辑2: 我看了一眼orkaround并试图实现它:

def loadFileToList(addressfile, dlg):
del addressList[:]
if os.path.exists(addressfile):
    if file_is_empty(addressfile):
        raiseException("Ungueltige Quelldatei! Quelldatei ist leer!")
        return -1
    else:
        #with open(addressfile, 'rb') as csvfile:
            #filereader = csv.reader(csvfile, delimiter=';')
        reader = unicode_csv_reader(open(addressfile))
        for row in reader:
            addressList.append(row)
        return addressList
else:
    raiseException("Pfad der Quelldatei nicht gefunden!")
    return -1


def unicode_csv_reader(utf8_data, dialect=csv.excel, **kwargs):
csv_reader = csv.reader(utf8_data, dialect=dialect, **kwargs)
for row in csv_reader:
    yield [unicode(cell, 'utf-8') for cell in row]

但现在我在执行代码时收到以下错误消息:   读者中的行:

  

文件“C:/Users/Constantin/.qgis2/python/plugins \ Geocoder \ logic.py”,   第46行,在unicode_csv_reader中       yield [行中单元格的unicode(cell,'utf-8')] UnicodeDecodeError:'utf8'编解码器无法解码位置19的字节0xdf:无效   继续字节

我只是不明白为什么它只是无法解码它-.-

更新:

我的csv文件中的一些行:

1190;Wien;Weinberggasse
1190;Wien;Hauptstraße
1190;Wien;Kärnterstraße

1 个答案:

答案 0 :(得分:1)

except的语法暗示您正在使用Python 2.但由于您在字符串中使用非ASCII(Unicode)字符,因此Python 3是一个明显更好的选择。你似乎在用德语工作,所以至少有一些ü和ß会潜入。

在Python 3中,阅读只是:

rows = []
with open('test.csv', encoding='utf-8') as csvfile:
    reader = csv.reader(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
    for row in reader:
        rows.append(row)

写作:

with open('testout.csv', mode="w", encoding='utf-8') as csvfile:
    writer = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
    for row in rows:
        writer.writerow(row)

请注意,读/写不是二进制,并且编码是理所当然的。结果正是您所期望的。类似的东西:

Artikelname;Menge
Äpfel;3
Bäume;12

正确编码所有字符。在磁盘上,数据是UTF-8编码的。在内存中,完整的Unicode。

如果你不能使用Python 3,那么你必须非常谨慎地对Unicode字符进行正确编码和解码,特别是在I / O边界 - 例如。读取和写入数据,或与PostgreSQL等外部系统通信时。现有代码至少有几种方法可以不用处理。例如,使用str()来转换不一定是ASCII字符的内容,以及缺少UTF-8编码。

不幸的是,Python 2中没有简单的修复.Python 2的CSV模块是 schrecklich kaput 。来自the docs:“csv模块不直接支持读写Unicode。” 2016年?!但是,有一些解决方法。其中一个食谱就在文档中。 This Stack Overflow answer重申它,并提供其他几种选择。

所以,如果可以,请使用Python 3。它将简化此问题和许多其他非ASCII I / O问题。否则,在其他SO答案中部署其中一个CSV解决方法。

<强>更新

如果您在使用变通方法时遇到问题,我也不喜欢标准答案。这是一个适合我的非规范读者解决方案:

import csv

rows = []
with open('test.csv', mode='rb') as csvfile:
    reader = csv.reader(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
    for row in reader:
        urow = [unicode(cell, 'utf-8') for cell in row]
        rows.append(urow)

print rows

这对Python 3来说绝对是不可移植的,但它可以工作,不需要导入任何其他模块。请注意,如果您使用的是IPython / Jupyter或交互式Python控制台(“REPL”),您将看到较低级别的字符串,例如:

[ [u'Artikelname', u'Menge'], 
  [u'\xc4pfel', u'3'], 
  [u'B\xe4ume', u'12] 
]

因此,字符串有\xc4,而不是一个漂亮,整洁的Ä。这很烦人,但没错。输入u'\u00c4pfel'可以为您提供相同的功能。并且很容易确认c4the correct Unicode code point。 Python 2在处理非ASCII字符方面做得很差。只有4,094个理由才能使用Python 3。

输出的手册等价物,顺便说一下:

with open('testout.csv', mode='wb') as csvfile:
    writer = csv.writer(csvfile, delimiter=';', quoting=csv.QUOTE_MINIMAL)
    for row in rows:
        urow = [cell.encode('utf-8') for cell in row]
        writer.writerow(urow)

所有这些完全取决于您的输入文件真正采用UTF-8编码。如果它们处于其他任何地方,那就会打开另一个可怕的腐烂水壶。