Python ile UTF8 CSV dosyası okumak


94

Python ile aksanlı karakterler içeren bir CSV dosyası okumaya çalışıyorum (sadece Fransızca ve / veya İspanyolca karakterler). Csvreader ( http://docs.python.org/library/csv.html ) için Python 2.5 belgelerine dayanarak , csvreader yalnızca ASCII'yi desteklediğinden, CSV dosyasını okumak için aşağıdaki kodu buldum.

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:
        ...

Aşağıda okumaya çalıştığım CSV dosyasının bir özeti var:

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
...

UTF-8'e kodlamayı / kod çözmeyi denememe rağmen, hala aşağıdaki istisnayı alıyorum:

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)

Bunu nasıl düzeltirim?


Martin, eğer buralarda olsaydın, kabul edilen yanıtı Martelli'nin Python 2 yanıtından değiştirmeyi düşünür müsün?
Antti Haapala

Yanıtlar:


114

.encodeYöntem, bir bayt dize yapmak için bir Unicode dize uygulanan alır; ama siz onu bir bayt dizgisiyle çağırıyorsunuz ... yanlış yoldan 'yuvarlak! Bak codecsstandart kütüphanede modül ve codecs.openUTF-8 kodlanmış metin dosyaları okumak için daha iyi genel çözümler için özellikle. Bununla birlikte, csvözellikle modül için, utf-8 verilerini iletmeniz gerekir ve zaten aldığınız şey budur, böylece kodunuz çok daha basit olabilir:

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 

Not: Giriş verilerinizin utf-8'de OLMADIĞI, ancak örneğin ISO-8859-1'de olmadığı ortaya çıkarsa, o zaman bir "kod dönüştürmeye" ihtiyacınız vardır ( csvmodül düzeyinde utf-8 kullanmak istiyorsanız ) , formun line.decode('whateverweirdcodec').encode('utf-8')- ama muhtemelen , ISO-8859- * kodlanmış bytestrings ile gerçekten iyi olacağı gibi , yieldyukarıdaki kodumdaki satırda sadece mevcut kodlamanızın adını kullanabilirsiniz .'utf-8'csv


4
Bu, python belgelerindeki (OP kopyalayıp yapıştırılan yer) örneğin yanlış olduğu anlamına mı geliyor? Unicode csv verdiğinizde kırılırsa yaptığı ekstra kodlama adımının anlamı nedir?
Anentropik


85

Python 2.X

Sorunlarınızı çözmesi gereken bir unicode-csv kitaplığı vardır, ayrıca csv ile ilgili herhangi bir yeni kod yazmaya gerek yoktur.

İşte benioku dosyalarından bir örnek:

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

Python 3'te bu, yerleşik csvmodül tarafından kutunun dışında desteklenir . Bu örneğe bakın:

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

11

Utf-8 kodlamalı bir CSV Dosyası okumak istiyorsanız, size önerdiğim minimalist bir yaklaşım şuna benzer bir şey kullanmanızdır:

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

Bu ifadeyle, daha sonra çalışmak için bir CSV okuyucu kullanabilirsiniz.


2
Bunun yalnızca Python 3 olması mümkün mü? It kabul etmez Python 2. benim için başarısız encodingiçindeopen
Zvika

@Zvika evet, python 3'te bu çözüm çalışıyor:open('file.csv', 'r', encoding="ISO8859")
luca76

Ayrıca open (file_name, "rt", encoding = 'utf-8'), yani dosyayı "metin oku" modunda aç
Jimmy Lee Jones

3

Ayrıca bu gönderideki yanıtı kontrol edin: https://stackoverflow.com/a/9347871/1338557

Ucsv.py adlı kitaplığın kullanılmasını önerir. Python 2.7 için kodlama problemini (utf-8) ele almak için yazılmış CSV'nin kısa ve basit değişimi. Ayrıca csv.DictReader için destek sağlar

Düzenleme : Kullandığım örnek kodu ekleme:

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'])})

Eğer bağlantı bozuk gider ihtimale karşı Cevabınız o bağlantının bazı ayrıntıları koymalıyız \
Yaje

# Downvoter- Neden işe yaramayacağını düşündüğünüzden emin değilim. Ucsv kitaplığı benim için gayet iyi çalıştı. 2 günden beri uğraştığım unicde hatasını çözmeye yardımcı oldum. Örnek bir kod arıyorsanız, burada düzenleme @ Yaje'ye gider - Bazı ayrıntıları verdim; ayrıca örnek kod. Ve bağlantı da düzeltildi, bu daha önce başka bir gönderiye işaret ediyordu.
Atripavan

Bir metin dosyasını ikili olarak açmanızın belirli bir nedeni var mı? 'rb' ikili dosyaları açmak içindir.
Codeguy007

2

Kullanılması codecs.openAlex Martelli bana faydası olduğu kanıtlanmıştır önerdi olarak.

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
Tüm CSV'lerle çalışmaz, aşağıdaki geçerli bir csv satırıdır: "Foo Bar; Baz"; 231; 313; ";;;"; 1;
jb.

csvModülü içe aktarırsınız ancak kullanmazsınız.
Christophe Roussy

1

Yardım sayfasına bağlantı python 2.6 için aynı ve bildiğim kadarıyla 2.5'ten beri csv modülünde bir değişiklik olmadı (hata düzeltmelerinin yanı sıra). Burada herhangi bir kodlama / kod çözme olmadan çalışan kod yer almaktadır (da.csv dosyası değişken verilerle aynı verileri içerir ). Dosyanızın herhangi bir dönüştürme olmadan doğru okunması gerektiğini varsayıyorum.

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

Acaba bu hangi python sürümünde çalışır? Hem 2.7 hem de 3.5 ile hata alıyorum. "ValueError: açmak için yeterli değerler (3 beklenen, var 1)"
eis

@eis: Sisteminizde virgülün varsayılan bir sınırlayıcı olmadığını tahmin edebiliyorum. delimiter=','Bunun yerine eklemeyi deneyin dialect=csv.excel.
minibüs

1

Sizin için hiçbir şey işe yaramadıysa, yolunuzdan kaçmayı unutmuş olabilirsiniz.
Örneğin, bu kod:

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

Bir hatayla sonuçlanır:

SyntaxError: (unicode hatası) 'unicodeescape' codec bileşeni 2-3 konumundaki baytların kodunu çözemiyor: kesilmiş \ UXXXXXXXX kaçış

Düzeltmek için şunları yapmanız yeterlidir:

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

0

Latin-1Unicode tablosuna baktığımda, 00E9" AKUT LATİN KÜÇÜK E HARFİ " karakter kodunu görüyorum . Bu, örnek verilerinizdeki vurgulu karakterdir. Basit bir test, bu karakter için kodlamanın unicode (neredeyse ) kodlamasından farklı Pythonolduğunu gösterir .UTF-8UTF-16

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

encode("UTF-8")Özel çağırmadan önce unicode verilerini denemenizi öneririm unicode_csv_reader(). Bir dosyadaki verileri basitçe okumak, kodlamayı gizleyebilir, bu nedenle gerçek karakter değerlerini kontrol edin.


0

Aynı sorunu başka bir sunucuda yaşadım, ancak yerel ayarların karışık olduğunu fark etti.

export LC_ALL="en_US.UTF-8"

sorunu çözdü

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.