Python 2 和 3 的 CSV 阅读器

12 投票
3 回答
12249 浏览
提问于 2025-04-16 12:55

我正在尝试使用csv模块来读取一个utf-8编码的csv文件,但在为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 个回答

0

我知道这个问题已经很老了,但我在找这个方法。就算有人看到这个,也许会觉得有用。

这是我解决问题的方法,感谢Lennart Regebro的提示:

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

更新: 虽然我最初的代码可以正常工作,但我现在发布了一个小工具包,地址是 https://pypi.python.org/pypi/csv342,它为 Python 2 提供了类似 Python 3 的接口。无论你用哪个版本的 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+ 的。在运行时,它会自动选择合适的版本。UTF8RecoderUnicodeReader 是直接复制自 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
17

确实,在Python 2中,打开文件时应该使用二进制模式,而在Python 3中则应该使用文本模式。另外,在Python 3中还需要指定newline=''这个参数(你忘记了)。

你需要在一个条件语句中进行文件的打开操作。

import sys

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


with infile as csvfile:
    ...

撰写回答