【问题标题】:Python: skip comment lines marked with # in csv.DictReaderPython:跳过 csv.DictReader 中标有 # 的注释行
【发布时间】:2012-12-18 23:50:35
【问题描述】:

使用csv.DictReader 处理 CSV 文件很棒 - 但我有带有注释行的 CSV 文件(由行首的哈希表示),例如:

# step size=1.61853
val0,val1,val2,hybridisation,temp,smattr
0.206895,0.797923,0.202077,0.631199,0.368801,0.311052,0.688948,0.597237,0.402763
-169.32,1,1.61853,2.04069e-92,1,0.000906546,0.999093,0.241356,0.758644,0.202382
# adaptation finished

csv 模块doesn't include any way to skip such lines.

我可以轻松地做一些 hacky,但我想有一种很好的方法可以将 csv.DictReader 包裹在其他迭代器对象周围,它会预处理以丢弃行。

【问题讨论】:

    标签: python csv comments


    【解决方案1】:

    实际上这与filter 配合得很好:

    import csv
    fp = open('samples.csv')
    rdr = csv.DictReader(filter(lambda row: row[0]!='#', fp))
    for row in rdr:
        print(row)
    fp.close()
    

    【讨论】:

    • 这会将整个文件读入内存。如果它不是太大那么没问题,否则你可能想要使用生成器表达式或itertools.ifilter()
    • ...或生成器表达式:csv.DictReader(row for row in fp if not row.startswith('#'))
    • @Duncan 在 Python3.6 中不需要 itertools,因为filter() 默认会返回一个迭代器,因此文件不会被加载到内存中。
    【解决方案2】:

    好问题。 Python 的 CSV 库缺乏对 cme​​ts 的基本支持(在 CSV 文件的顶部并不少见)。虽然 Dan Stowell 的解决方案适用于 OP 的特定情况,但其局限性在于 # 必须作为第一个符号出现。更通用的解决方案是:

    def decomment(csvfile):
        for row in csvfile:
            raw = row.split('#')[0].strip()
            if raw: yield raw
    
    with open('dummy.csv') as csvfile:
        reader = csv.reader(decomment(csvfile))
        for row in reader:
            print(row)
    

    例如,以下dummy.csv文件:

    # comment
     # comment
    a,b,c # comment
    1,2,3
    10,20,30
    # comment
    

    返回

    ['a', 'b', 'c']
    ['1', '2', '3']
    ['10', '20', '30']
    

    当然,这同样适用于csv.DictReader()

    【讨论】:

    • 我相信你在 decomment() 函数中的意思是“yield row”而不是“yield raw”。 CSV 文件可以在字符串中包含 # 个字符,并且完全有效。
    • @ThibaultReuille:确实很多 CSV 文件可以在字符串中包含 #,尽管 CSV 格式没有很好地标准化。我的意思是yield raw。我的建议无论如何都不会处理字符串中的#。
    • @ThibaultReuille:您所指的正是为什么不建议手动为库可以为您做的事情输入大量代码;您可能不会在第一次得到所有细节(例如,您也可以在字符串中包含换行符),并且这会占用您实际解决的任务的时间。我认为我的解决方案可以快速解决应该在csv 中的问题。如果它需要相当大的扩展才能为您工作,也许您应该考虑另一个 csv 库,例如 pandas 中的那个。希望对您有所帮助。
    【解决方案3】:

    另一种读取 CSV 文件的方法是使用 pandas

    这是一个示例代码:

    df = pd.read_csv('test.csv',
                     sep=',',     # field separator
                     comment='#', # comment
                     index_col=0, # number or label of index column
                     skipinitialspace=True,
                     skip_blank_lines=True,
                     error_bad_lines=False,
                     warn_bad_lines=True
                     ).sort_index()
    print(df)
    df.fillna('no value', inplace=True) # replace NaN with 'no value'
    print(df)
    

    对于这个 csv 文件:

    a,b,c,d,e
    1,,16,,55#,,65##77
    8,77,77,,16#86,18#
    #This is a comment
    13,19,25,28,82
    

    我们会得到这个输出:

           b   c     d   e
    a                     
    1    NaN  16   NaN  55
    8   77.0  77   NaN  16
    13  19.0  25  28.0  82
               b   c         d   e
    a                             
    1   no value  16  no value  55
    8         77  77  no value  16
    13        19  25        28  82
    

    【讨论】:

    • pandas 确实是一个强大的库,但它是一个需要设置和学习使用的依赖项。而且,作者已经在问题中表示他只是想使用内置的csv.DictReader模块,并且多年前已经提供了相关答案。我不明白您为什么要添加此解决方案作为替代方案。
    • 问题的作者可能不需要熊猫。但这个论坛的目的不仅仅是帮助每个问题的作者解决他们的具体问题。
    • @GrannyAching .sort_index() 究竟在这里实现了什么? :)
    【解决方案4】:

    只是从@sigvaldm 的解决方案中发布错误修复。

    def decomment(csvfile):
    for row in csvfile:
        raw = row.split('#')[0].strip()
        if raw: yield row
    
    with open('dummy.csv') as csvfile:
        reader = csv.reader(decomment(csvfile))
        for row in reader:
            print(row)
    

    CSV 行可以在带引号的字符串中包含“#”字符并且完全有效。以前的解决方案是切断包含“#”字符的字符串。

    【讨论】:

    • 当 cmets 在行尾跟随时,这将不起作用,例如,a,b,c # comment
    猜你喜欢
    • 2014-03-03
    • 2011-06-14
    • 2013-12-09
    • 2011-11-27
    • 2015-02-26
    • 2013-08-24
    • 2012-06-01
    • 2015-09-10
    • 1970-01-01
    相关资源
    最近更新 更多