在 Python 中处理 CSV 文件

作者:Mitch Frazier

正如我的一个朋友常说的那样,“标准的优点在于有很多可以选择”。以 CSV 文件为例。 CSV 当然代表“逗号分隔值”,但通常情况下,CSV 文件似乎使用制表符而不是逗号来分隔值。 甚至不要提及字段引用。 如果您处理 CSV 文件并且您使用 Python,那么csv模块可以使您的生活更轻松。

在 Python 中处理 CSV 文件可能再简单不过了。 例如,让我们使用以下包含 3 列“A”、“B”和“C D”的 CSV 文件

  $ cat test.csv
  A,B,"C D"
  1,2,"3 4"
  5,6,7

以下 python 程序读取它并显示其内容

import csv

ifile  = open('test.csv', "rb")
reader = csv.reader(ifile)

rownum = 0
for row in reader:
    # Save header row.
    if rownum == 0:
        header = row
    else:
        colnum = 0
        for col in row:
            print '%-8s: %s' % (header[colnum], col)
            colnum += 1
            
    rownum += 1

ifile.close()

运行时产生

  $ python csv1.py 
  A       : 1
  B       : 2
  C D     : 3 4
  A       : 5
  B       : 6
  C D     : 7

此外,csv模块提供了用于编写 CSV 文件的 writer 对象。 以下 Python 程序将我们的测试 CSV 文件转换为使用制表符作为值分隔符并且所有值都用引号引起来的 CSV 文件。 在创建 writer 时,指定了分隔符字符和引号字符,以及何时/如何引用。 创建 reader 对象时也可以使用相同的选项。

import csv

ifile  = open('test.csv', "rb")
reader = csv.reader(ifile)
ofile  = open('ttest.csv', "wb")
writer = csv.writer(ofile, delimiter='\t', quotechar='"', quoting=csv.QUOTE_ALL)

for row in reader:
    writer.writerow(row)

ifile.close()
ofile.close()

运行结果

  $ python csv2.py
  $ cat ttest.csv
  "A"     "B"     "C D"
  "1"     "2"     "3 4"
  "5"     "6"     "7"

我开始使用csv模块时的首要任务是编写一个函数,试图在打开 CSV 文件之前确定其格式,以便我可以处理逗号、制表符和不同的引用约定

import os
import sys
import csv

def opencsv(filename):
    tfile = open(filename, "r")
    line  = tfile.readline()
    tfile.close()
    if   line[0] == '"':
        quote_char = '"'
        quote_opt  = csv.QUOTE_ALL
    elif line[0] == "'":
        quote_char = "'"
        quote_opt  = csv.QUOTE_ALL
    else:
        quote_char = '"'
        quote_opt  = csv.QUOTE_MINIMAL
    
    if   line.find('\t') != -1:
        delim_char = '\t'
    else:
        delim_char = ','
    
    tfile  = open(filename, "rb")
    reader = csv.reader(tfile, delimiter=delim_char, quotechar=quote_char, quoting=quote_opt)
    return (tfile, reader)

由于我是csv模块的新手,并且犯了未阅读整个“手册”页面的常见错误,我当然没有注意到csv模块已经包含了一个名为Sniffer的类来执行此操作。 我将使用它作为读者的练习(在这种情况下,也是作者的练习)。

Mitch Frazier 是 Emerson Electric Co. 的嵌入式系统程序员。 自 2000 年代初以来,Mitch 一直是Linux Journal的贡献者和朋友。

加载 Disqus 评论