Читайте и файлы CSV Записи включая unicode с Python 2.7

Я плохо знаком с Python, и у меня есть вопрос о том, как использовать Python, чтобы прочитать и записать файлы CSV. Мой файл содержит как Германия, французский язык, и т.д. Согласно моему коду, файлы могут быть считаны правильно в Python, но когда я пишу это в новый файл CSV, unicode становится некоторыми странными символами.

Данные похожи: enter image description here

И мой код:

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

И результат похож: enter image description here

Скажите мне, что я должен сделать для решения проблемы?Большое спасибо!

62
задан 24 June 2013 в 18:48

6 ответов

Поскольку str в python2 bytes на самом деле. Таким образом, если хотят записать unicode в csv, необходимо закодировать unicode к str использование utf-8 кодирование.

def py2_unicode_to_str(u):
    # unicode is only exist in python2
    assert isinstance(u, unicode)
    return u.encode('utf-8')

Использование class csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds):

  • py2
    • csvfile: open(fp, 'w')
    • ключ передачи и значение в [1 111], которые кодируются [1 112] <ул.> <литий> writer.writerow({py2_unicode_to_str(k): py2_unicode_to_str(v) for k,v in row.items()})
  • py3
    • csvfile: open(fp, 'w')
    • передают нормальный dict, содержит str как [1 117] к [1 118]

Наконец код

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)

Заключение

В python3, просто используйте unicode str.

В python2, используйте unicode текст дескриптора, используйте str, когда ввод-вывод произойдет.

4
ответ дан 31 October 2019 в 13:36

Я не мог ответить Mark выше, но я просто сделал одну модификацию, которая зафиксировала ошибку, которая была вызвана, если данные в ячейках не были unicode, т.е. или международными данными плавающими. Я заменил эту строку в функцию UnicodeWriter: "self.writer.writerow ([s.encode ("utf-8"), если тип (типы) == типы. UnicodeType еще s для s последовательно])" так, чтобы это стало:

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)

необходимо будет также "импортировать типы".

2
ответ дан 31 October 2019 в 13:36

Другая альтернатива:

Используют код от 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

Этим модулем является API, совместимый с STDLIB csv модуль.

53
ответ дан 31 October 2019 в 13:36

Удостоверьтесь, что Вы кодируете и декодируете как соответствующие.

Этот пример будет распространение в прямом и обратном направлениях некоторый текст в качестве примера в utf-8 к файлу CSV и отступать для демонстрации:

# -*- 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])

Печать:

German         Chinese        French         
Straße         中國的            français       
auslösen       英語             américaine     
zerstören      美國人            épais  
51
ответ дан 31 October 2019 в 13:36

Существует пример в конце csv документация модуля , который демонстрирует, как иметь дело с Unicode. Ниже копируется непосредственно с того пример . Обратите внимание, что строковое чтение или записанный будет строками Unicode. Не передавайте строку байтов UnicodeWriter.writerows, например.

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)

Вход (закодированный UTF-8):

American,美国人
French,法国人
German,德国人

Вывод:

"American","美国人"
"French","法国人"
"German","德国人"
30
ответ дан 31 October 2019 в 13:36

У меня была та же самая проблема. Ответ - то, что Вы уже делаете его правильно. Это - проблема MS Excel. Попытайтесь открыть файл с другим редактором, и Вы заметите, что Ваше кодирование уже было успешно. Для создания MS Excel счастливый переместитесь от UTF-8 до UTF-16. Это должно работать:

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)
2
ответ дан 31 October 2019 в 13:36

Другие вопросы по тегам:

Похожие вопросы: