Lesen einer UTF8-CSV-Datei mit Python


93

Ich versuche, eine CSV-Datei mit Akzentzeichen mit Python zu lesen (nur französische und / oder spanische Zeichen). Basierend auf der Python 2.5-Dokumentation für den csvreader ( http://docs.python.org/library/csv.html ) habe ich den folgenden Code zum Lesen der CSV-Datei entwickelt, da der csvreader nur ASCII unterstützt.

def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
    # csv.py doesn't do Unicode; encode temporarily as UTF-8:
    csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
                            dialect=dialect, **kwargs)
    for row in csv_reader:
        # decode UTF-8 back to Unicode, cell by cell:
        yield [unicode(cell, 'utf-8') for cell in row]

def utf_8_encoder(unicode_csv_data):
    for line in unicode_csv_data:
        yield line.encode('utf-8')

filename = 'output.csv'
reader = unicode_csv_reader(open(filename))
try:
    products = []
    for field1, field2, field3 in reader:
        ...

Unten finden Sie einen Auszug aus der CSV-Datei, die ich zu lesen versuche:

0665000FS10120684,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Bleu
0665000FS10120689,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Gris
0665000FS10120687,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Vert
...

Obwohl ich versuche, in UTF-8 zu codieren / decodieren, erhalte ich immer noch die folgende Ausnahme:

Traceback (most recent call last):
  File ".\Test.py", line 53, in <module>
    for field1, field2, field3 in reader:
  File ".\Test.py", line 40, in unicode_csv_reader
    for row in csv_reader:
  File ".\Test.py", line 46, in utf_8_encoder
    yield line.encode('utf-8', 'ignore')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 68: ordinal not in range(128)

Wie behebe ich das?


Martin, wenn Sie in der Nähe sind, würden Sie in Betracht ziehen, die akzeptierte Antwort von Martellis Python 2-Antwort zu ändern.
— Antti Haapala

Antworten:


113

Die .encodeMethode wird auf eine Unicode-Zeichenfolge angewendet, um eine Byte-Zeichenfolge zu erstellen. aber du rufst es stattdessen auf einer Byte-Zeichenfolge auf ... falsch herum! Schaue auf diecodecs Modul in der Standardbibliothek an und codecs.opensuchen Sie insbesondere nach besseren allgemeinen Lösungen zum Lesen von UTF-8-codierten Textdateien. csvInsbesondere für das Modul müssen Sie jedoch utf-8-Daten übergeben, und das erhalten Sie bereits, damit Ihr Code viel einfacher sein kann:

import csv

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]

filename = 'da.csv'
reader = unicode_csv_reader(open(filename))
for field1, field2, field3 in reader:
  print field1, field2, field3 

PS: Wenn sich herausstellt, dass Ihre Eingabedaten NICHT in utf-8, sondern z. B. in ISO-8859-1 vorliegen, benötigen Sie eine "Transcodierung" (wenn Sie utf-8 auf csvModulebene verwenden möchten ). , der Form line.decode('whateverweirdcodec').encode('utf-8')- aber wahrscheinlich können Sie einfach den Namen Ihrer vorhandenen Codierung in der yieldZeile in meinem Code oben verwenden, anstatt 'utf-8', wie csves mit ISO-8859- * codierten Bytestrings eigentlich in Ordnung sein wird.


4
Bedeutet dies, dass das Beispiel in den Python-Dokumenten (wo OP kopiert und eingefügt wurde) falsch ist? Was ist der Sinn des zusätzlichen Codierungsschritts, der ausgeführt wird, wenn er unterbrochen wird, wenn Sie ihm eine Unicode-CSV geben?
— Anentropic


80

Python 2.X.

Es gibt eine Unicode-CSV- Bibliothek, die Ihre Probleme lösen sollte, mit dem zusätzlichen Vorteil, dass Sie nicht navigieren müssen, um neuen CSV-bezogenen Code zu schreiben.

Hier ist ein Beispiel aus ihrer Readme:

>>> import unicodecsv
>>> from cStringIO import StringIO
>>> f = StringIO()
>>> w = unicodecsv.writer(f, encoding='utf-8')
>>> w.writerow((u'é', u'ñ'))
>>> f.seek(0)
>>> r = unicodecsv.reader(f, encoding='utf-8')
>>> row = r.next()
>>> print row[0], row[1]
é ñ

Python 3.X.

In Python 3 wird dies vom integrierten csvModul sofort unterstützt. Siehe dieses Beispiel:

import csv
with open('some.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

8

Wenn Sie eine CSV-Datei mit der Codierung utf-8 lesen möchten, empfehle ich Ihnen einen minimalistischen Ansatz: Gehen Sie wie folgt vor:

with open(file_name, encoding="utf8") as csv_file:

Mit dieser Anweisung können Sie später einen CSV-Reader zum Arbeiten verwenden.


2
Ist es möglich, dass dies nur Python 3 ist? Es schlägt für mich in Python 2 fehl. Es akzeptiert das encodinginopen
— Zvika

@ Zvika ja, in Python 3 funktioniert diese Lösung:open('file.csv', 'r', encoding="ISO8859")
— Luca76

Ich würde auch open hinzufügen (Dateiname, "rt", encoding = 'utf-8'), dh offene Datei im Modus "Text lesen"
— Jimmy Lee Jones

3

Überprüfen Sie auch die Antwort in diesem Beitrag: https://stackoverflow.com/a/9347871/1338557

Es wird die Verwendung der Bibliothek ucsv.py vorgeschlagen. Kurzer und einfacher Ersatz für CSV, der geschrieben wurde, um das Codierungsproblem (utf-8) für Python 2.7 zu beheben. Bietet auch Unterstützung für csv.DictReader

Bearbeiten : Hinzufügen von Beispielcode, den ich verwendet habe:

import ucsv as csv

#Read CSV file containing the right tags to produce
fileObj = open('awol_title_strings.csv', 'rb')
dictReader = csv.DictReader(fileObj, fieldnames = ['titles', 'tags'], delimiter = ',', quotechar = '"')
#Build a dictionary from the CSV file-> {<string>:<tags to produce>}
titleStringsDict = dict()
for row in dictReader:
    titleStringsDict.update({unicode(row['titles']):unicode(row['tags'])})

Sie sollten einige Details dieses Links in Ihre Antwort
— einfügen

# Downvoter- Ich bin mir nicht sicher, warum du es für nutzlos gehalten hast. Die UCSV-Bibliothek hat für mich gut funktioniert. Hat geholfen, den Unicde-Fehler zu beheben, mit dem ich seit 2 Tagen zu kämpfen hatte. Wenn Sie nach einem Beispielcode gesucht haben, finden Sie ihn hier im edit @ Yaje. Ich habe einige Details angegeben. auch der Beispielcode. Und korrigierte auch den Link, der früher auf einen anderen Beitrag verwies.
— Atripavan

Gibt es einen bestimmten Grund, warum Sie eine Textdatei als Binärdatei öffnen? 'rb' dient zum Öffnen von Binärdateien.
— Codeguy007

2

Die Verwendung, codecs.openwie Alex Martelli vorgeschlagen hatte, erwies sich für mich als nützlich.

import codecs

delimiter = ';'
reader = codecs.open("your_filename.csv", 'r', encoding='utf-8')
for line in reader:
    row = line.split(delimiter)
    # do something with your row ...

3
Es würde nicht mit allen CSVs funktionieren. Es folgt eine gültige CSV-Zeile: "Foo Bar; Baz"; 231; 313; ";;;"; 1;
— jb.

Sie importieren das csvModul, verwenden es aber nicht.
— Christophe Roussy

1

Der Link zur Hilfeseite ist der gleiche für Python 2.6 und meines Wissens gab es seit 2.5 keine Änderung im CSV-Modul (abgesehen von Fehlerkorrekturen). Hier ist der Code, der nur ohne Codierung / Decodierung funktioniert (Datei da.csv enthält dieselben Daten wie die variablen Daten ). Ich gehe davon aus, dass Ihre Datei ohne Konvertierungen korrekt gelesen werden sollte.

test.py:

## -*- coding: utf-8 -*-
#
# NOTE: this first line is important for the version b) read from a string(unicode) variable
#

import csv

data = \
"""0665000FS10120684,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Bleu
0665000FS10120689,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Gris
0665000FS10120687,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Vert"""

# a) read from a file
print 'reading from a file:'
for (f1, f2, f3) in csv.reader(open('da.csv'), dialect=csv.excel):
    print (f1, f2, f3)

# b) read from a string(unicode) variable
print 'reading from a list of strings:'
reader = csv.reader(data.split('\n'), dialect=csv.excel)
for (f1, f2, f3) in reader:
    print (f1, f2, f3)

da.csv:

0665000FS10120684,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Bleu
0665000FS10120689,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Gris
0665000FS10120687,SD1200IS,Appareil photo numérique PowerShot de 10 Mpx de Canon avec trépied (SD1200IS) - Vert

Ich frage mich, in welcher Python-Version würde das funktionieren? Ich erhalte Fehler mit 2.7 und 3.5. "ValueError: nicht genügend Werte zum Entpacken (erwartete 3, bekam 1)"
— Eis

@eis: Ich kann mir vorstellen, dass Komma auf Ihrem System kein Standardtrennzeichen ist. Versuchen Sie , fügen delimiter=','statt dialect=csv.excel.
— van

1

Wenn nichts für Sie funktioniert hat, haben Sie möglicherweise vergessen, Ihrem Weg zu entkommen.
Zum Beispiel dieser Code:

f = open("C:\Some\Path\To\file.csv")

Würde zu einem Fehler führen:

SyntaxError: (Unicode-Fehler) Der Codec 'unicodeescape' kann keine Bytes an Position 2-3 dekodieren: abgeschnittenes \ UXXXXXXXX-Escape

Um dies zu beheben, gehen Sie einfach wie folgt vor:

f = open("C:\\Some\\Path\\To\\file.csv")

0

Wenn ich mir die Latin-1Unicode-Tabelle ansehe , sehe ich den Zeichencode 00E9" LATIN SMALL LETTER E WITH ACUTE ". Dies ist das akzentuierte Zeichen in Ihren Beispieldaten. Ein einfacher Test in Pythonzeigt, dass sich die UTF-8Codierung für dieses Zeichen von der (fast UTF-16) Unicode- Codierung unterscheidet.

>>> u'\u00e9'
u'\xe9'
>>> u'\u00e9'.encode('utf-8')
'\xc3\xa9'
>>> 

Ich schlage vor, Sie versuchen es mit encode("UTF-8")den Unicode-Daten, bevor Sie das Special aufrufen unicode_csv_reader(). Durch einfaches Lesen der Daten aus einer Datei wird möglicherweise die Codierung ausgeblendet. Überprüfen Sie daher die tatsächlichen Zeichenwerte.


0

Hatte das gleiche Problem auf einem anderen Server, stellte jedoch fest, dass die Gebietsschemas durcheinander sind.

export LC_ALL="en_US.UTF-8"

Das Problem wurde behoben

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.