2016-11-22 3 views
1

Я работаю над программой, где я хочу сравнивать адреса, которые я прочитал из файла csv, в базу данных postgres. (Его плагин для QGis) Я могу успешно установить соединение, а также прочитать данные из базы данных, пока я отправляю запросы без моих собственных параметров.Проблемы с кодированием Python с PostgreSQL Database

Так что я делаю: Я прочитал csv-файл и сохранил его в списке. Затем я выбираю выходной файл. Затем я нажимаю кнопку, которая при щелчке должна сравнивать записи в файле csv с записями в моей базе данных. Если запись из файла csv (почтовый индекс, город, адрес) имеет те же самые свойства в базе данных, я записываю ее в список «Успешные совпадения», если один из них не соответствует, я записываю его в список «Список ошибок» .)

Моя проблема сейчас происходит, когда я исполняю заявление со своими собственными параметрами СКП Сообщение об ошибке я получаю обратно говорит:

Invalid Byte-Sequence for Encoding 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 

Спасибо!

EDIT: Когда я показываю адрес, содержащий специальный charachter он показывает, как «Hauptstra \ xdfe» вместо «Хауптштрассы Извините им плохо с кодировкой, это юникод Значит ли это, что получить посылает к базы данных, как это и я СВАО кодировать его по-разному

EDIT 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] 

Но теперь я получаю следующее сообщение об ошибке при выполнении код: для строки в читателя:

File "C:/Users/Constantin/.qgis2/python/plugins\Geocoder\logic.py", line 46, in unicode_csv_reader yield [unicode(cell, 'utf-8') for cell in row] UnicodeDecodeError: 'utf8' codec can't decode byte 0xdf in position 19: invalid continuation byte

Я просто не понимаю, почему он просто не могу расшифровать это -.-

UPDATE:

Некоторые строки из моего файла CSV:

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

Возможный дубликат [недействительной последовательности байтов для кодирования «UTF8»] (http://stackoverflow.com/questions/4867272/invalid-byte-sequence-for-encoding-utf8) – Jason

+0

Я проверил свою базу данных и в разделе Свойства -> Определить -> Кодирование говорит utf8 ... –

ответ

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. В памяти полный Юникод.

Если вы не можете использовать Python 3, то вы должны принять отличные, чтобы символы Юникода были правильно закодированы и декодированы, особенно на границах ввода-вывода - например. при чтении и записи данных или при общении с внешней системой, такой как PostgreSQL. Есть, по крайней мере, несколько способов, чтобы код в его нынешнем виде не заботился. Использование str() для приведения точных символов, не обязательно символов ASCII, например, и отсутствия кодировки UTF-8.

К сожалению, нет никакого тривиального исправления в Python 2. CSV-модуль Python 2: schrecklich kaput. От the docs: «Модуль csv напрямую не поддерживает чтение и запись Unicode». В 2016 году ?! Однако есть обходные пути. Один из рецептов находится прямо в документах. This Stack Overflow answer повторяет его и предоставляет несколько других альтернатив.

Итак, используйте Python 3, если сможете. Это упростит этот и многие другие проблемы ввода-вывода, отличные от ASCII. В противном случае разверните один из обходных путей CSV в этом другом ответе SO.

Update

Если у вас возникли проблемы с использованием обходных путей, мне не нравится стандартный ответ либо. Вот неканонической решение читатель, который работает для меня:

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' дает вам то же самое. И легко подтвердить, что c4 - the 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 кодировке. Если они что-то еще, это открывает еще один ужасный чайник гниющих рыб.

+0

Спасибо Джонатан за ваш ответ! Это школьный проект, и для нашего партнера по проекту нам действительно нужно использовать Python 2.7.5, потому что это его требования ... Я взгляну на ссылку, чтобы проверить обходные пути. Большое спасибо, я бы никогда не подумал об этом ;-) –

+0

В общем, объявление 'from codecs import open', а затем' open (..., encoding = "utf-8") '- отличный способ сделать Python 2 значительно облегчает работу с файлами ввода/вывода Unicode. Он работает в обеих версиях и предоставляет Python 2 около возможностей Python 3. Чтение и запись автоматически кодируются. К сожалению, CSV - особый случай. Модуль 'csv' Python 2 безнадежен с Unicode и нуждается в многоуровневой няни. –

+0

Эй, я взглянул на другую команду «Переполнение стека» вокруг ответа и попытался ее реализовать. Теперь при получении кода появляется следующее сообщение об ошибке: Файл «C: /Users/Constantin/.qgis2/python/plugins \ Geocoder \ logic.py», строка 35, в loadFileToList для строки в считывателе: Файл «C : /Users/Constantin/.qgis2/python/plugins \ Geocoder \ logic.py ", строка 46, в unicode_csv_reader выход [unicode (ячейка, 'utf-8') для ячейки в строке] UnicodeDecodeError: 'utf8' codec не может декодировать байт 0xdf в позиции 19: недопустимый байт продолжения. Я изменил код, см. Мой первый пост –

Смежные вопросы