【问题标题】:Why does csv.DictReader skip empty lines?为什么 csv.DictReader 会跳过空行?
【发布时间】:2015-02-26 17:51:11
【问题描述】:

似乎csv.DictReader 会跳过空行,即使设置了restval。使用以下内容,将跳过输入文件中的空行:

import csv
CSV_FIELDS = ("field1", "field2", "field3")
for row in csv.DictReader(open("f"), fieldnames=CSV_FIELDS, restval=""):
    if not row or not row[CSV_FIELDS[0]]:
        sys.exit("never reached, why?")

文件f 在哪里:

1,2,3


a,b,c

【问题讨论】:

  • 期望的行为是什么?
  • 如果您有一个只有 2 个逗号的空行,即,,,则将打印"never reached, why?"。这就是你想要的吗?
  • 对于它的价值,这是我所期望的行为,我什至声称这应该是显而易见的:空行不是空记录,它是 absence i> 的记录。
  • @mdurant:当字段少于应有的字段时,缺少的字段为restval。至少那是我对doc 的解释
  • @KonradRudolph:这可能是您所期望的,但这不是我对文档的解释。在我的场景中,我想知道行何时为空,或者当所有值都丢失时以不同的方式表示。

标签: python file csv


【解决方案1】:

Inside the csv.DictReader class:

    # unlike the basic reader, we prefer not to return blanks,
    # because we will typically wind up with a dict full of None
    # values
    while row == []:
        row = self.reader.next()

所以空行被跳过。 如果您不想跳过空行,可以改用csv.reader

另一种选择是继承csv.DictReader

import csv
CSV_FIELDS = ("field1", "field2", "field3")

class MyDictReader(csv.DictReader):
    def next(self):
        if self.line_num == 0:
            # Used only for its side effect.
            self.fieldnames
        row = self.reader.next()
        self.line_num = self.reader.line_num

        d = dict(zip(self.fieldnames, row))
        lf = len(self.fieldnames)
        lr = len(row)
        if lf < lr:
            d[self.restkey] = row[lf:]
        elif lf > lr:
            for key in self.fieldnames[lr:]:
                d[key] = self.restval
        return d

for row in MyDictReader(open("f", 'rb'), fieldnames=CSV_FIELDS, restval=""):
    print(row)

产量

{'field2': '2', 'field3': '3', 'field1': '1'}
{'field2': '', 'field3': '', 'field1': ''}
{'field2': '', 'field3': '', 'field1': ''}
{'field2': 'b', 'field3': 'c', 'field1': 'a'}

【讨论】:

  • 啊太棒了...从阅读器到 DictReader 的行为不同,感谢您发现这一点
  • woa 很干净,可以在 2.6 中开箱即用,非常感谢! (另外你不介意回答我觉得很酷的问题)
【解决方案2】:

这是你的文件:

1,2,3
,,
,,
a,b,c

我加了昏迷,现在他拿了两个空行{'field2': '', 'field3': '', 'field1': ''} 对于restval 参数,它只是说如果您设置了字段但缺少一个,则其他值转到该值。

所以你设置了三个字段,每次都有三个值。但是我们在这里讨论的是“列”而不是行。

你的行是空的,所以他跳过了它,除非你用逗号指定他需要为 dictreader 取空值。

【讨论】:

    【解决方案3】:

    Unutbu 已经指出了发生这种情况的原因,无论如何,快速解决方法是将空行替换为',',然后将它们传递给DictReader,然后restval 将处理其余的事情。

    CSV_FIELDS = ("field1", "field2", "field3")
    
    with open('test.csv') as f:
        lines = (',' if line.isspace() else line for line in f)
        for row in csv.DictReader(lines, fieldnames=CSV_FIELDS, restval=""):
            print row
    
    #output
    {'field2': '2', 'field3': '3', 'field1': '1'}
    {'field2': '', 'field3': '', 'field1': ''}
    {'field2': '', 'field3': '', 'field1': ''}
    {'field2': 'b', 'field3': 'c', 'field1': 'a'}
    

    更新:

    如果是多行空值,上面的代码不会这样做,在这种情况下你可以像这样使用csv.reader

    RESTVAL = ''
    
    with open('test.csv') as f:
        for row in csv.reader(f, quotechar='"'):
            if not row:
                # Don't use `dict.fromkeys` if RESTVAL is a mutable object
                # {k: RESTVAL for k in CSV_FIELDS}
                print dict.fromkeys(CSV_FIELDS, RESTVAL)
            else:
                print {k: v if v else RESTVAL for k, v in zip(CSV_FIELDS, row)}
    

    如果文件包含:

    1,2,"
    
    
    4"
    
    
    a,b,c
    

    那么输出将是:

    {'field2': '2', 'field3': '\n\n\n4', 'field1': '1'}
    {'field2': '', 'field3': '', 'field1': ''}
    {'field2': '', 'field3': '', 'field1': ''}
    {'field2': 'b', 'field3': 'c', 'field1': 'a'}
    

    【讨论】:

    • 谢谢你,但我在现实生活中的 CSV 文件中有多个行值。
    • @isonix 多行值是什么意思?
    • 空行可以是单个值的一部分,而不仅仅是“所有值都缺少 csv 空行”。
    • 看起来很酷,我正在尝试,谢谢!为什么quotechar='"'
    • @isonix 我的示例输入使用" 处理多行数据。
    猜你喜欢
    • 2013-12-09
    • 2011-06-14
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    相关资源
    最近更新 更多