如果将CSV重新定义为“字符分隔值”,即使用任何单个字符(但通常为非任何字符)的数据,那么自动检测文件实际为CSV 的可靠方式是什么?字母数字符号)作为分隔符,而不仅仅是逗号?
基本上,使用此(重新)定义, CSV = DSV (“分隔符分隔值”),例如,在此Wikipedia article中讨论,而“逗号分隔”值“格式在RFC 4180中定义。
更具体地说,是否有一种方法用于统计推断数据具有某种“固定”长度,这意味着“可能的CSV”?仅计算分隔符的数量并不总是有效,因为存在每个记录可变数量的字段的CSV文件(即,与RFC 4180强制要求相反的记录,具有相同数量的跨同一文件的字段)。
CSV识别似乎是一个特别具有挑战性的问题,特别是如果检测不能基于文件扩展名(例如,在读取无论如何没有此类信息的流时)。
正确(“完整”)自动检测至少需要做出4个决定:
由于其他数据集(例如,使用逗号的自由文本)的相似性,完全自动检测似乎没有单一的解决方案,特别是对于诸如可变长度记录,单引号或双引号字段等极端情况或多行记录。
因此,最好的方法似乎是望远镜检测,其中在应用CSV之前检查也可以归类为CSV的格式(例如,像Apache CLF这样的日志文件格式)检测规则。
即使像Excel这样的商业应用程序似乎依赖于文件扩展名(.csv)来决定(1),这显然不是自动检测,尽管如果应用程序被告知数据是CSV,问题会大大简化
以下是一些讨论(2)和(3)的启发式的好相关文章:
引用类型(4)的检测可以基于处理文件中的几行并查找相应的值(例如,每行的偶数'或'表示单引号或双引号)这样的处理可以通过初始化现有的CSV解析器(例如,OpenCSV)来完成,该解析器将适当地处理CSV行分离(例如,多行事件)。
但是(1)呢,即首先确定数据是否为CSV?
数据挖掘可以帮助做出此决定吗?
答案 0 :(得分:6)
如果您不能限制用作分隔符的内容,那么您可以使用暴力。
您可以遍历引号字符,列分隔符和记录分隔符的所有可能组合(对于ASCII,256 * 255 * 254 = 16581120)。
id,text,date
1,"Bob says, ""hi
..."", with a sigh",1/1/2012
删除所有引用的列,这可以通过RegEx替换来完成。
//quick javascript example of the regex, you'd replace the quote char with whichever character your currently testing
var test='id,text,date\n1,"bob, ""hi\n..."", sigh",1/1/2011';
console.log(test.replace(/"(""|.|\n|\r)*?"/gm,""));
id,text,date
1,,1/1/2012
拆分记录分隔符
["id,text,date", "1,,1/1/2012"]
拆分列分隔符上的记录
[ ["id", "text", "date"], ["1", "", "1/1/2012"] ]
如果每条记录的列数匹配,您会有一些CSV置信度。
3 == 3
如果列数不匹配,请尝试使用行,列和引号字符的其他组合
修改的
在对分隔符有信心并检查列类型一致性之后实际解析数据可能是一个有用的额外步骤
可以使用的CSV数据(行,列)越多,您就可以从此方法中提取的信心越强。
我认为这个问题有点愚蠢/过于笼统,如果你有一堆未知数据,你肯定要首先检查所有“低悬的果实”。二进制格式通常具有相当不同的标题签名,然后有易于检测的文本格式的XML和JSON。
答案 1 :(得分:1)
总会有非CSV文件看起来像CSV,反之亦然。例如,frankc在您引用的Java链接中发布了一个病态(但完全有效)的CSV文件:
Name
Jim
Tom
Bill
我认为,最好的方法是对文件为CSV的可能性进行某种启发式估计。我能想到的一些启发式方法是:
人们可能会想到其他启发式方法。然后,方法是开发基于这些的评分算法。下一步是对已知CSV和非CSV文件的集合进行评分。如果存在足够明显的分离,那么评分可能被认为是有用的,分数应告诉您如何设置检测阈值。