Membaca file CSV UTF8 dengan Python

94

Saya mencoba membaca file CSV dengan karakter beraksen dengan Python (hanya karakter Prancis dan / atau Spanyol). Berdasarkan dokumentasi Python 2.5 untuk csvreader ( http://docs.python.org/library/csv.html ), saya menemukan kode berikut untuk membaca file CSV karena csvreader hanya mendukung ASCII.

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

Di bawah ini adalah ekstrak file CSV yang saya coba baca:

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

Meskipun saya mencoba menyandikan / mendekode ke UTF-8, saya masih mendapatkan pengecualian berikut:

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)

Bagaimana cara mengatasinya?

Martin
sumber
Martin, jika Anda ada, apakah Anda akan mempertimbangkan untuk mengganti jawaban yang diterima dari jawaban hanya Martelli's Python 2.
Antti Haapala

Jawaban:

114

The .encodeMetode akan diterapkan ke string Unicode untuk membuat byte-string; tapi Anda menyebutnya dengan byte-string ... dengan cara yang salah 'bulat! Lihat codecsmodul di pustaka standar dan codecs.openkhususnya untuk solusi umum yang lebih baik untuk membaca file teks berenkode UTF-8. Namun, untuk csvmodul khususnya, Anda harus meneruskan data utf-8, dan itulah yang sudah Anda dapatkan, sehingga kode Anda bisa jauh lebih sederhana:

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 

NB: jika ternyata data input Anda BUKAN di utf-8, tetapi misalnya di ISO-8859-1, maka Anda memang membutuhkan "transcoding" (jika Anda ingin menggunakan utf-8 di csvlevel modul) , dari bentuk line.decode('whateverweirdcodec').encode('utf-8')- tapi mungkin Anda bisa menggunakan nama pengkodean yang ada di yieldbaris dalam kode saya di atas, alih-alih 'utf-8', seperti csvyang sebenarnya akan baik-baik saja dengan ISO-8859- * encoded bytestrings.

Alex Martelli
sumber
4
Apakah ini berarti contoh di dokumen python (di mana OP copy & paste) salah? Apa gunanya langkah pengkodean tambahan yang dilakukannya jika rusak ketika Anda memberikannya csv unicode?
Anentropik
84

Python 2.X

Ada pustaka unicode-csv yang akan memecahkan masalah Anda, dengan manfaat tambahan tidak perlu menulis kode terkait csv baru.

Berikut adalah contoh dari readme mereka:

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

Di python 3 ini didukung di luar kotak oleh csvmodul build-in . Lihat contoh ini:

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

Jika Anda ingin membaca File CSV dengan pengkodean utf-8, pendekatan minimalis yang saya rekomendasikan adalah menggunakan sesuatu seperti ini:

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

Dengan pernyataan itu, nanti Anda dapat menggunakan pembaca CSV untuk bekerja dengannya.

Nick Cuevas
sumber
2
Apakah mungkin ini hanya Python 3? Gagal untuk saya, dengan Python 2. Tidak menerima encodinginopen
Zvika
@ Zvika ya, di python 3 solusi ini berfungsi:open('file.csv', 'r', encoding="ISO8859")
luca76
Saya juga akan menambahkan buka (nama_file, "rt", encoding = 'utf-8'), yaitu, buka file dalam mode "baca teks"
Jimmy Lee Jones
3

Juga periksa jawabannya di posting ini: https://stackoverflow.com/a/9347871/1338557

Ini menyarankan penggunaan pustaka yang disebut ucsv.py. Pengganti singkat dan sederhana untuk CSV yang ditulis untuk mengatasi masalah encoding (utf-8) untuk Python 2.7. Juga menyediakan dukungan untuk csv.DictReader

Edit : Menambahkan kode contoh yang saya gunakan:

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'])})
Atripavan
sumber
Anda harus memasukkan beberapa detail dari tautan itu di jawaban Anda, untuk berjaga-jaga jika tautannya rusak \
Yaje
# Downvoter- Tidak yakin mengapa Anda pikir itu tidak ada gunanya. Perpustakaan ucsv bekerja dengan baik untuk saya. Membantu mengatasi kesalahan unicde yang telah saya perjuangkan sejak 2 hari. Jika Anda mencari beberapa contoh kode, ini dia di edit @ Yaje- Saya telah memberikan beberapa detail; juga kode sampel. Dan mengoreksi tautannya juga, yang sebelumnya mengarah ke beberapa pos lain.
Atripavan
Adakah alasan khusus Anda membuka file teks sebagai biner? 'rb' untuk membuka file biner.
Codeguy007
2

Menggunakan codecs.openseperti yang disarankan Alex Martelli terbukti berguna bagi saya.

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 ...
pengguna1154664
sumber
3
Ini tidak akan bekerja dengan semua CSV, berikut adalah baris csv yang valid: "Foo Bar; Baz"; 231; 313; ";;;"; 1;
jb.
Anda mengimpor csvmodul tetapi tidak menggunakannya.
Christophe Roussy
1

Tautan ke halaman bantuan sama untuk python 2.6 dan sejauh yang saya tahu tidak ada perubahan dalam modul csv sejak 2.5 (selain perbaikan bug). Berikut adalah kode yang hanya bekerja tanpa pengkodean / decoding (file da.csv berisi data yang sama sebagai variabel data yang ). Saya berasumsi bahwa file Anda harus dibaca dengan benar tanpa konversi apa pun.

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
mobil van
sumber
Saya ingin tahu versi python mana yang akan berfungsi? Saya mendapatkan kesalahan dengan 2.7 dan 3.5. "ValueError: tidak cukup nilai untuk dibongkar (diharapkan 3, didapat 1)"
eis
@eis: Saya dapat membayangkan bahwa di sistem Anda koma bukanlah pembatas default. Coba tambahkan, delimiter=','bukan dialect=csv.excel.
van
1

Perlu dicatat bahwa jika tidak ada yang berhasil untuk Anda, Anda mungkin lupa untuk melarikan diri.
Misalnya, kode ini:

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

Akan mengakibatkan kesalahan:

SyntaxError: (unicode error) Codec 'unicodeescape' tidak dapat mendekode byte di posisi 2-3: terpotong \ UXXXXXXXX escape

Untuk memperbaikinya, cukup lakukan:

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

Melihat Latin-1tabel unicode , saya melihat kode karakter 00E9" LATIN SMALL LETTER E WITH ACUTE ". Ini adalah karakter beraksen dalam data sampel Anda. Pengujian sederhana dalam Pythonmenunjukkan bahwa UTF-8pengkodean untuk karakter ini berbeda dari UTF-16pengkodean unicode (hampir ).

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

Saya sarankan Anda mencoba encode("UTF-8")data unicode sebelum memanggil khusus unicode_csv_reader(). Hanya membaca data dari file mungkin menyembunyikan pengkodean, jadi periksa nilai karakter sebenarnya.

gimel
sumber
0

Memiliki masalah yang sama di server lain, tetapi menyadari bahwa lokal kacau.

export LC_ALL="en_US.UTF-8"

memperbaiki masalah

Piotr Pęczek
sumber