Je suis nouveau sur Python, et j’ai une question sur la façon d’utiliser Python pour lire et écrire des fichiers CSV. Mon fichier contient des informations comme l’Allemagne, le Français, etc. Selon mon code, les fichiers peuvent être lu correctement en Python, mais lorsque je l’écris dans un nouveau fichier CSV, l’unicode devient des caractères étranges.
Les données sont comme:
Et mon code est:
import csv
f=open('xxx.csv','rb')
reader=csv.reader(f)
wt=open('lll.csv','wb')
writer=csv.writer(wt,quoting=csv.QUOTE_ALL)
wt.close()
f.close()
Et le résultat est comme:
Pourriez-vous me dire ce que je devrais faire pour résoudre le problème? Merci beaucoup!
Une autre alternative:
Utilisez le code du paquet unicodecsv ...
https://pypi.python.org/pypi/unicodecsv/
>>> import unicodecsv as csv
>>> from io import BytesIO
>>> f = BytesIO()
>>> w = csv.writer(f, encoding='utf-8')
>>> _ = w.writerow((u'é', u'ñ'))
>>> _ = f.seek(0)
>>> r = csv.reader(f, encoding='utf-8')
>>> next(r) == [u'é', u'ñ']
True
Ce module est compatible API avec le module csv STDLIB.
Assurez-vous d’encoder et de décoder comme il convient.
Cet exemple retournera un exemple de texte dans utf-8 vers un fichier csv et reviendra pour montrer:
# -*- coding: utf-8 -*-
import csv
tests={'German': [u'Straße',u'auslösen',u'zerstören'],
'French': [u'français',u'américaine',u'épais'],
'Chinese': [u'中國的',u'英語',u'美國人']}
with open('/tmp/utf.csv','w') as fout:
writer=csv.writer(fout)
writer.writerows([tests.keys()])
for row in Zip(*tests.values()):
row=[s.encode('utf-8') for s in row]
writer.writerows([row])
with open('/tmp/utf.csv','r') as fin:
reader=csv.reader(fin)
for row in reader:
temp=list(row)
fmt=u'{:<15}'*len(temp)
print fmt.format(*[s.decode('utf-8') for s in temp])
Impressions:
German Chinese French
Straße 中國的 français
auslösen 英語 américaine
zerstören 美國人 épais
Il existe un exemple à la fin de documentation du module csv qui montre comment traiter Unicode. Ci-dessous est copié directement à partir de cela exemple . Notez que les chaînes lues ou écrites seront des chaînes Unicode. Ne passez pas une chaîne d'octets à UnicodeWriter.writerows
, par exemple.
import csv,codecs,cStringIO
class UTF8Recoder:
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
return self.reader.next().encode("utf-8")
class UnicodeReader:
def __init__(self, f, dialect=csv.Excel, encoding="utf-8-sig", **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
'''next() -> unicode
This function reads and returns the next line as a Unicode string.
'''
row = self.reader.next()
return [unicode(s, "utf-8") for s in row]
def __iter__(self):
return self
class UnicodeWriter:
def __init__(self, f, dialect=csv.Excel, encoding="utf-8-sig", **kwds):
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
'''writerow(unicode) -> None
This function takes a Unicode string and encodes it to the output.
'''
self.writer.writerow([s.encode("utf-8") for s in row])
data = self.queue.getvalue()
data = data.decode("utf-8")
data = self.encoder.encode(data)
self.stream.write(data)
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)
with open('xxx.csv','rb') as fin, open('lll.csv','wb') as fout:
reader = UnicodeReader(fin)
writer = UnicodeWriter(fout,quoting=csv.QUOTE_ALL)
for line in reader:
writer.writerow(line)
Entrée (codée UTF-8):
American,美国人
French,法国人
German,德国人
Sortie:
"American","美国人"
"French","法国人"
"German","德国人"
Parce que str
dans python2 est bytes
en fait. Donc, si vous voulez écrire unicode
sur CSV, vous devez encoder unicode
à str
à l'aide de l'encodage utf-8
.
def py2_unicode_to_str(u):
# unicode is only exist in python2
assert isinstance(u, unicode)
return u.encode('utf-8')
Utilisez class csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', dialect='Excel', *args, **kwds)
:
csvfile
: open(fp, 'w')
bytes
qui sont codés avec utf-8
writer.writerow({py2_unicode_to_str(k): py2_unicode_to_str(v) for k,v in row.items()})
csvfile
: open(fp, 'w')
str
comme row
à writer.writerow(row)
Enfin code
import sys
is_py2 = sys.version_info[0] == 2
def py2_unicode_to_str(u):
# unicode is only exist in python2
assert isinstance(u, unicode)
return u.encode('utf-8')
with open('file.csv', 'w') as f:
if is_py2:
data = {u'Python中国': u'Python中国', u'Python中国2': u'Python中国2'}
# just one more line to handle this
data = {py2_unicode_to_str(k): py2_unicode_to_str(v) for k, v in data.items()}
fields = list(data[0])
writer = csv.DictWriter(f, fieldnames=fields)
for row in data:
writer.writerow(row)
else:
data = {'Python中国': 'Python中国', 'Python中国2': 'Python中国2'}
fields = list(data[0])
writer = csv.DictWriter(f, fieldnames=fields)
for row in data:
writer.writerow(row)
En python3, utilisez simplement l'unicode str
.
En python2, utilisez unicode
handle text, utilisez str
lorsque des E/S se produisent.
Je ne pouvais pas répondre à Mark ci-dessus, mais je venais d'apporter une modification qui corrigeait l'erreur provoquée si les données des cellules n'étaient pas unicode, c'est-à-dire des données float ou int. J'ai remplacé cette ligne dans la fonction UnicodeWriter: "self.writer.writerow ([s.encode (" utf-8 ")) si type (s) == types.UnicodeType sinon pour s en rangée]) de sorte qu'il devienne :
class UnicodeWriter:
def __init__(self, f, dialect=csv.Excel, encoding="utf-8-sig", **kwds):
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
'''writerow(unicode) -> None
This function takes a Unicode string and encodes it to the output.
'''
self.writer.writerow([s.encode("utf-8") if type(s)==types.UnicodeType else s for s in row])
data = self.queue.getvalue()
data = data.decode("utf-8")
data = self.encoder.encode(data)
self.stream.write(data)
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)
Vous devrez également "importer des types".
J'ai eu le même problème. La réponse est que vous le faites déjà bien. C'est le problème de MS Excel. Essayez d’ouvrir le fichier avec un autre éditeur et vous remarquerez que votre encodage a déjà réussi. Pour rendre MS Excel heureux, passez de UTF-8 à UTF-16. Cela devrait fonctionner:
class UnicodeWriter:
def __init__(self, f, dialect=csv.Excel_tab, encoding="utf-16", **kwds):
# Redirect output to a queue
self.queue = StringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
# Force BOM
if encoding=="utf-16":
import codecs
f.write(codecs.BOM_UTF16)
self.encoding = encoding
def writerow(self, row):
# Modified from original: now using unicode(s) to deal with e.g. ints
self.writer.writerow([unicode(s).encode("utf-8") for s in row])
# Fetch UTF-8 output from the queue ...
data = self.queue.getvalue()
data = data.decode("utf-8")
# ... and reencode it into the target encoding
data = data.encode(self.encoding)
# strip BOM
if self.encoding == "utf-16":
data = data[2:]
# write to the target stream
self.stream.write(data)
# empty queue
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)