python csv阅读器的问题-对我的喜好不够严格

Posted

技术标签:

【中文标题】python csv阅读器的问题-对我的喜好不够严格【英文标题】:Troubles with python csv reader - not strict enough for my liking 【发布时间】:2014-02-12 16:28:33 【问题描述】:

人们一直在问这个问题是关于什么的,所以我会尝试总结一下 - 我正在尝试实现检测用于解析 CSV 文件的最佳匹配格式的方法。这可能是对我正在尝试做的最好的描述。

我有包含这些内容的 csv 文件:

710000 8454889 03 3 ;sometext;;48,05;65,82;;65,82
710001 8454889 03 3 ;sometext;;49,09;66,96;;66,96
710002 8454889 03 3 ;sometext;;12,63;17,22;;17,22

没有引号字符和“;”作为分隔符。

我已经描述了几种 csv 阅读器方言:

csv.register_dialect('excel', delimiter = ',', quotechar = '"', quoting = csv.QUOTE_ALL, strict = True, skipinitialspace = True)
csv.register_dialect('semicolonquotes', delimiter = ';', quotechar = '"', quoting = csv.QUOTE_ALL, strict = True, skipinitialspace = True)
csv.register_dialect('semicolonnonquotes', delimiter = ';', quotechar = None, quoting = csv.QUOTE_NONE, strict = True, skipinitialspace = True)

我有一个脚本,它试图找出其中一种格式与文件内容最匹配。不幸的是,对于这个示例文件,它匹配第一种情况 - “excel”,即使我希望它只匹配“分号”。

编辑: 我用来匹配文件的代码是这样的:

dialects = csv.list_dialects()
for dialect in dialects:
    file.seek(0)
    reader = csv.reader(file, csv.get_dialect(dialect))
    reader.next()

非常简单的代码,用于查看阅读器在使用 set dialect 阅读时是否抛出错误。包裹在 try/except 中以无错误地捕捉第一种方言。不幸的是,这些方言都不会引发错误。

/编辑

我想如果我将 strict (link) 设置为 True,那么当行不包含引号字符时,它会引发错误。但显然它不是那样工作的。

第一个方言匹配,并得到我的 csv 行,如:

['710000 8454889 03 3 ;sometext;;48', '05;65', '82;;65', '82']

有什么方法可以调整这个,所以我会得到我想要的结果:

['710000 8454889 03 3 ', 'sometext', '', '48,05', '65,82', '', '65,82']

编辑2

通读文档,似乎为 csv.reader 指定引用几乎没有:http://docs.python.org/2.7/library/csv.html#csv.QUOTE_ALL

猜猜这就是我的问题所在。

/Edit2

免责声明:我知道 CSV 代表逗号分隔值。如果不扩展现有库就无法实现我想要的,那么我将接受它作为答案并强制用户使用仅包含逗号作为分隔符的 CSV 文件。

【问题讨论】:

您使用什么代码来检测 CSV 方言? @MartijnPieters - 在编辑中添加了一些代码。 首先检查最严格的方言是否有帮助,然后再检查最严格的方言,等等?你能把所有的方言都按严格排序吗? 是的,我可以。我实际上认为它们是按这个顺序排列的。因为这个“分号”是其中最不严格的——只需要 ;作为分隔符。整个问题是文件包含“,”作为小数分隔符而不是字段作为分隔符。在我看来,csv 阅读器应该首先查找引号字符,然后查找分隔符。我猜它可能就是这样做的。但我有点希望如果文件中缺少引号字符,它也会引发错误。 现在,CSV 代表字符分隔值。 【参考方案1】:

我不确定我是否明白你在问什么。但是,如果您知道分隔符是什么并且没有引号,请忘记 csv 方言,只需将这些内容指定为创建的 csv.reader 实例的格式参数:

with open('contents.csv', 'rb') as file:
    reader = csv.reader(file, delimiter=';', quotechar=None)
    line = reader.next()
    print 'line 1: '.format(line)

输出:

line 1: ['710000 8454889 03 3 ', 'sometext', '', '48,05', '65,82', '', '65,82']

【讨论】:

我想我要问的是如何编写可靠的 csv 格式检测。导致客户端可以上传具有不同分隔符的 csv 格式文件,使用“;”和“,”是最常见的。而且由于“,”可以用作小数分隔符,我不能只将分隔符设置为值。我必须能够测试格式并使用最佳匹配。如果这是不可能的,那么我想我会排除不同格式的选项。【参考方案2】:

我认为,如果您想让脚本自动找出要使用的最佳 csv 方言,则不应将其基于是否会引发错误,而应基于某种方言的执行情况(如果在全部)。

“大多数”CSV 将在每一行中具有相似数量的列(通常将第一行作为标题)。您可以使用此假设构建一个测试用例,以测试每种方言中每一行的列数 [列表长度] 的差异。在解析所有行或较小的样本后,列数差异最小(或重复出现数最高)的方言应该是最好的。如果出现平局,您可能需要想出更多的诡计,但这应该可以为您提供一个起点。

只要知道,一旦您开始接收没有任何订单的 csv,这种假设就会严重失败。这实际上一直在发生。

【讨论】:

我认为我发现的最糟糕的事情是,这个 csv 解析是如此“松散”,即使我将可用的 csv 格式减少到类似“;”作为分隔符和 '"' 作为quotechar,那么第一个文件仍将通过阅读器启动。另外我觉得做其他格式验证方法也不会削减它。文件可能很大并且使用像你描述的方法资源密集型系统,可能是不必要的。如果字段内容与数据类型不匹配,我想我会让这些文件通过初始验证,然后在此过程中稍后抛出错误

以上是关于python csv阅读器的问题-对我的喜好不够严格的主要内容,如果未能解决你的问题,请参考以下文章

为 CSV 阅读器引用 Python 字典中的键

CSV阅读器(Python)中的“行包含NULL字节”

Python CSV 阅读器将 Row 作为列表返回

rails 检查现有实例属性

无和空字符串的 CSV 阅读器行为

阅读csv文件Anaconda | Python 3