【问题标题】:Reading formatted text using python使用python读取格式化文本
【发布时间】:2012-02-29 00:02:43
【问题描述】:

我想用python读写以下格式的文件:

#h -F, field1 field2 field3
a,b,c
d,e,f
# some comments
g,h,i

此文件与典型的 CSV 非常相似,但以下内容除外:

  1. 标题行以#h 开头
  2. 标题行的第二个元素是表示分隔符的标记
  3. 标题的其余元素是字段名称(始终由单个空格分隔)
  4. 注释行总是以 # 开头,并且可以分散在整个文件中

有什么方法可以使用 csv.DictReader() 和 csv.DictWriter() 来读写这些文件?

【问题讨论】:

标签: python csv


【解决方案1】:

你可以单独解析第一行找到分隔符和字段名:

    firstline = next(f).split()
    delimiter = firstline[1][-1]
    fields = firstline[2:]

请注意,csv.DictReader 可以将任何可迭代对象作为其第一个参数。因此,要跳过 cmets,您可以将 f 包装在一个仅产生非注释行的迭代器 (skip_comments) 中:

import csv
def skip_comments(iterable):
    for line in iterable:
        if not line.startswith('#'):
            yield line

with open('data.csv','rb') as f:
    firstline = next(f).split()
    delimiter = firstline[1][-1]
    fields = firstline[2:]
    for line in csv.DictReader(skip_comments(f),
                               delimiter = delimiter, fieldnames = fields):
        print line

根据您发布的数据产生的结果

{'field2': 'b', 'field3': 'c', 'field1': 'a'}
{'field2': 'e', 'field3': 'f', 'field1': 'd'}
{'field2': 'h', 'field3': 'i', 'field1': 'g'}

要以这种格式写入文件,您可以使用 header 辅助函数:

def header(delimiter,fields):
    return '#h -F{d} {f}\n'.format(d = delimiter, f=' '.join(fields))

with open('data.csv', 'rb') as f:
    with open('output.csv', 'wb') as g:
        firstline = next(f).split()
        delimiter = firstline[1][-1]
        fields = firstline[2:]
        writer = csv.DictWriter(g, delimiter = delimiter, fieldnames = fields)
        g.write(header(delimiter,fields))
        for row in csv.DictReader(skip_comments(f),
                                   delimiter = delimiter, fieldnames = fields):
            writer.writerow(row)
            g.write('# comment\n')

请注意,您可以使用g.write(用于标题或注释行)或writer.writerow(用于 csv)写信给output.csv

【讨论】:

  • 不错。现在假设我想使用这种准 CSV 格式(即使用问题中提到的四个特性)写入文件。我将如何使用 csv.DictWriter 来做到这一点?
【解决方案2】:

假设输入文件以input 打开。首先,读入标题:

header = input.readline()

解析分隔符和字段名称并使用它来构造DictReader。现在,代替input,向读者提供表达式

(ln for ln in input where ln[0] != '#')

跳过 cmets。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 2018-12-17
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多