在Python中写入固定宽度、以空格分隔的CSV输出

7 投票
3 回答
7950 浏览
提问于 2025-04-16 15:35

我想用Python的csv写入器来写一个固定宽度、用空格分隔并且尽量少用引号的CSV文件。下面是我想要的输出示例:

item1           item2  
"next item1"    "next item2"
anotheritem1    anotheritem2  

如果我使用

writer.writerow( ("{0:15s}".format(item1), "{0:15s}".format(item2)) )
...

那么,由于使用了空格作为分隔符,格式就会出问题,因为在项目格式化时会因为尾部的空格而添加引号或转义字符(这取决于csv.QUOTE_*常量):

"item1          " "item2          "
"next item1     " "next item2     "
"anotheritem1   " "anotheritem2   "

当然,我可以自己格式化所有内容:

writer.writerow( ("{0:15s}{1:15s}".format(item1, item2)) )

但这样的话,使用csv写入器就没什么意义了。而且,我还得手动处理那些项目中嵌入空格的情况,这时候就需要用到引号或转义字符。换句话说,我似乎需要一个(并不存在的)"QUOTE_ABSOLUTELYMINIMAL"的csv常量,它的作用和"QUOTE_MINIMAL"一样,但会忽略尾部的空格。

有没有办法实现"QUOTE_ABSOLUTELYMINIMAL"的效果,或者用Python的CSV模块得到一个固定宽度、用空格分隔的CSV输出呢?

我想要CSV文件的固定宽度特性是为了更好地阅读。这样在读取和写入时都能作为CSV处理,但由于列的结构,阅读起来会更清晰。读取没有问题,因为csv的skipinitialspace选项可以忽略多余的空格。令我惊讶的是,写入似乎成了一个问题……

编辑:我得出的结论是,使用当前的csv插件是不可能实现的。这不是一个内置选项,我也看不出有什么合理的方法可以手动实现,因为似乎没有办法通过Python的csv写入器写入额外的分隔符而不使用引号或转义字符。因此,我可能得自己写一个csv写入器。

3 个回答

0

这个活跃状态的示例教你如何在Python中输出表格格式的数据:

http://code.activestate.com/recipes/267662-table-indentation/

你可能能从这个例子中获取到足够的信息,来完成你想做的事情。

2

这对你有什么帮助呢?我觉得你其实只是缺少了 csv.QUOTE_NONE 这个常量。

import csv
csv.register_dialect('spacedelimitedfixedwidth', delimiter=' ', quoting=csv.QUOTE_NONE)
with open('crappymainframe.out', 'rb') as f:
    reader = csv.reader(f, 'spacedelimitedfixedwidth')

这是对 csv 模块文档底部的 unixpwd 方言示例的一个修改。

8

你遇到的基本问题是,CSV格式和固定格式的数据存储方式其实是两种完全不同的思路。让它们一起工作并不是常见的做法。而且,如果你只在有空格的项目上加了引号,这会导致那些行的对齐出现问题:

testing     "rather hmm "
strange     "ways to    "
"store some " "csv data   "
testing     testing    

把这些数据读回来时也会得到错误的结果:

'testing' 'rather hmm '
'strange' 'ways to    '
'store some ' 'csv data   '
'testing' 'testing' ''

注意最后一行多出来的字段。考虑到这些问题,我建议你使用你的例子:

"item1          " "item2          "
"next item1     " "next item2     "
"anotheritem1   " "anotheritem2   "

这个格式我觉得非常易读,使用现有的CSV库生成也很简单,而且读回来时解析得也很正确。下面是我用来生成它的代码:

import csv

class SpaceCsv(csv.Dialect):
    "csv format for exporting tables"
    delimiter = None
    doublequote = True
    escapechar = None
    lineterminator = '\n'
    quotechar = '"'
    skipinitialspace = True
    quoting = csv.QUOTE_MINIMAL
csv.register_dialect('space', SpaceCsv)

data = (
        ('testing    ', 'rather hmm '),
        ('strange    ', 'ways to    '),
        ('store some ', 'csv data   '),
        ('testing    ', 'testing    '),

temp = open(r'c:\tmp\fixed.csv', 'w')
writer = csv.writer(temp, dialect='space')
for row in data:
    writer.writerow(row)
temp.close()

当然,你需要确保所有数据的长度都是一致的,这可以在进入处理这些数据的函数之前,或者在函数内部进行调整。哦,如果你有数字数据,也要考虑到它们的填充问题。

撰写回答