Python 2 и 3 CSV-ридер - PullRequest
       11

Python 2 и 3 CSV-ридер

10 голосов
/ 03 марта 2011

Я пытаюсь использовать модуль csv для чтения CSV-файла utf-8, и у меня возникли некоторые проблемы при создании общего кода для python 2 и 3 из-за кодировки.

Вот оригинальный код в Python 2.7:

with open(filename, 'rb') as csvfile:
    csv_reader = csv.reader(csvfile, quotechar='\"')
    langs = next(csv_reader)[1:]
    for row in csv_reader:
        pass

Но когда я запускаю его с python 3, ему не нравится тот факт, что я открываю файл без «кодирования». Я попробовал это:

with codecs.open(filename, 'r', encoding='utf-8') as csvfile:
    csv_reader = csv.reader(csvfile, quotechar='\"')
    langs = next(csv_reader)[1:]
    for row in csv_reader:
        pass

Теперь python 2 не может декодировать строку в цикле «for». Итак ... как мне это сделать?

Ответы [ 3 ]

14 голосов
/ 03 марта 2011

Действительно, в Python 2 файл должен быть открыт в двоичном режиме, но в Python 3 в текстовом режиме. Также в Python 3 newline='' должно быть указано (что вы забыли).

Вам нужно будет открыть файл в блоке if.

import sys

if sys.version_info[0] < 3: 
    infile = open(filename, 'rb')
else:
    infile = open(filename, 'r', newline='', encoding='utf8')


with infile as csvfile:
    ...
2 голосов
/ 05 декабря 2014

Обновление : хотя код в моем исходном ответе работает, я тем временем выпускаю небольшой пакет на https://pypi.python.org/pypi/csv342, который предоставляет интерфейс, подобный Python 3 для Python 2. Так что независимо от вашей версии Python выможет просто сделать

import csv342 as csv
import io
with io.open('some.csv', 'r', encoding='utf-8', newline='') as csv_file:
    for row in csv.reader(csv_file, delimiter='|'):
        print(row)

Оригинальный ответ : Вот решение, которое даже с Python 2 фактически декодирует текст в строки Unicode и, следовательно, работает с кодировками, отличными от UTF-8.

Приведенный ниже код определяет функцию csv_rows(), которая возвращает содержимое файла в виде последовательности списков.Пример использования:

for row in csv_rows('some.csv', encoding='iso-8859-15', delimiter='|'):
    print(row)

Вот два варианта для csv_rows(): один для Python 3+ и другой для Python 2.6+.Во время выполнения он автоматически выбирает правильный вариант.UTF8Recoder и UnicodeReader являются дословными копиями примеров в документации по библиотеке Python 2.7 .

import csv
import io
import sys


if sys.version_info[0] >= 3:
    # Python 3 variant.
    def csv_rows(csv_path, encoding, **keywords):
        with io.open(csv_path, 'r', newline='', encoding=encoding) as csv_file:
            for row in csv.reader(csv_file, **keywords):
                yield row

else:
    # Python 2 variant.
    import codecs

    class UTF8Recoder:
        """
        Iterator that reads an encoded stream and reencodes the input to UTF-8
        """
        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:
        """
        A CSV reader which will iterate over lines in the CSV file "f",
        which is encoded in the given encoding.
        """

        def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
            f = UTF8Recoder(f, encoding)
            self.reader = csv.reader(f, dialect=dialect, **kwds)

        def next(self):
            row = self.reader.next()
            return [unicode(s, "utf-8") for s in row]

        def __iter__(self):
            return self


    def csv_rows(csv_path, encoding, **kwds):
        with io.open(csv_path, 'rb') as csv_file:
            for row in UnicodeReader(csv_file, encoding=encoding, **kwds):
                yield row
0 голосов
/ 20 августа 2013

Старый вопрос, я знаю, но я искал, как это сделать. На всякий случай, если кто-нибудь придет по этому поводу и может оказаться полезным.

Вот так я и решил, спасибо Леннарту Регебро за подсказку. :

if sys.version > '3':
       rd = csv.reader(open(input_file, 'r', newline='',
       encoding='iso8859-1'), delimiter=';', quotechar='"')
else:
       rd = csv.reader(open(input_file, 'rb'), delimiter=';',
       quotechar='"')

тогда делай то, что тебе нужно:

for row in rd:
       ......
...