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

Posted

技术标签:

【中文标题】在 Python 中编写固定宽度、空格分隔的 CSV 输出【英文标题】:writing fixed width, space delimited CSV output in Python 【发布时间】:2011-08-04 01:05:11 【问题描述】:

我想使用 Python 的 csv writer 编写一个固定宽度、空格分隔和最少引用的 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:15s1:15s".format(item1, item2)))

但是使用 csv 编写器并没有多大意义。此外,当空间嵌入到项目中并且应该使用引用/转义时,我将不得不手动整理这些情况。换句话说,我似乎需要一个(不存在的)“QUOTE_ABSOLUTELYMINIMAL”csv 常量,它可以充当“QUOTE_MINIMAL”,但也会忽略尾随空格。

有没有办法实现“QUOTE_ABSOLUTELYMINIMAL”行为或使用 Python 的 CSV 模块获得固定宽度、空格分隔的 CSV 输出?

我想要 CSV 文件中的固定宽度功能的原因是更好的可读性。因此它将被处理为 CSV 用于读取和写入,但由于列结构,可读性更好。读取不是问题,因为 csv skipinitialspace 选项会忽略多余的空格。令我惊讶的是,写作似乎是一个问题......

编辑:我得出结论,使用当前的 csv 插件是不可能实现的。它不是一个内置选项,我看不到如何手动实现它的任何合理方法,因为似乎没有办法在不引用或转义它们的情况下由 Python 的 csv 编写器编写额外的分隔符。因此,我可能不得不编写自己的 csv 编写器。

【问题讨论】:

【参考方案1】:

这个活动状态配方展示了如何在 python 中输出表格化数据: http://code.activestate.com/recipes/267662-table-indentation/

您也许可以从该示例中收集到足够的信息来做您想做的事情。

【讨论】:

感谢您的回答。但是,您链接的代码不使用 Python 的 csv 插件,也不适用于 csv 输出。当然可以编写我自己的 csv 编写器,但我希望有一种方法可以为此目的使用 Python 编写器......【参考方案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 方言示例的修改。

【讨论】:

我看不到这个阅读器示例如何解决编写器问题? csv.QUOTE_NONE 也无济于事 - 在这种情况下,项目的尾随空格在写入时会被转义。【参考方案3】:

您遇到的基本问题是 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()

当然,您需要将所有数据填充到相同的长度,或者在到达执行所有这些操作的函数之前,或者在函数本身中。哦,如果你有数字数据,你也必须为此留出填充余量。

【讨论】:

以上是关于在 Python 中编写固定宽度、空格分隔的 CSV 输出的主要内容,如果未能解决你的问题,请参考以下文章

读取固定宽度格式,其中宽度是从列标题中推断出来的

在 spark java 中读取具有固定宽度和分隔符的文本文件

查找连续重复单词时的Python后视正则表达式“固定宽度模式”错误

将以逗号分隔格式保存的数据转换为不带包的固定宽度格式

对总计超过200万条记录(行)的多个输入文件(固定空格分隔的42列txt文件)进行合并排序和合并

Spark-Scala:使用异常处理将固定宽度线解析为 Dataframe Api