Scala:自动检测CSV文件中的分隔符/分隔符

Scala:自动检测CSV文件中的分隔符/分隔符,scala,csv,split,separator,opencsv,Scala,Csv,Split,Separator,Opencsv,我正在使用OpenCSV库分割我的CSV文件。现在我需要绝对确定地检测分隔符/分隔符。 我在网上搜索过,但我只找到了一些例子,你可以创建一个候选名单,然后尝试其中一个。我认为这不是最好的方法,因为你很可能会出错。 我的拆分器应该在任何CSV(我没有控制权)上正常工作,因此它必须尽可能通用。 有人有好的解决方案吗?您可能已经看到了这一点,它列出了一些好的策略,例如计算潜在分隔符出现的次数,和/或在使用假设的分隔符时验证每行的列数是否相同 不幸的是,绝对确定性是不可能的,因为该格式没有在文件中明确指

我正在使用OpenCSV库分割我的CSV文件。现在我需要绝对确定地检测分隔符/分隔符。 我在网上搜索过,但我只找到了一些例子,你可以创建一个候选名单,然后尝试其中一个。我认为这不是最好的方法,因为你很可能会出错。 我的拆分器应该在任何CSV(我没有控制权)上正常工作,因此它必须尽可能通用。
有人有好的解决方案吗?

您可能已经看到了这一点,它列出了一些好的策略,例如计算潜在分隔符出现的次数,和/或在使用假设的分隔符时验证每行的列数是否相同

不幸的是,绝对确定性是不可能的,因为该格式没有在文件中明确指定分隔符的方法。我认为使其尽可能通用的最佳解决方案是让用户指定何时不是逗号(这是opencsv处理它的方式),或者如果您或他们确定自动检测失败,则允许客户端指定分隔符。如果这不能是交互式的,那么我认为你能做的最好的事情就是记录你认为失败的案例,以便他们以后处理

此外,我认为错误率将低于您的预期。我猜99%的时间分隔符是逗号、分号、句号或制表符。不幸的是,我看到懒惰的程序员在假设数据不包含字段的情况下,使用插入符号、管道或平铺来分隔字段,因此他们不必进行适当的转义。但这不是标准,也不应该被视为CSV


Python csv模块有一个猜测分隔符的类(用户提供候选项列表);您可能想看看它。

我最近一直在处理CSV文件的分隔符/分隔符检测问题。我提出了以下建议,我希望这些建议能帮助其他人,或许还能收到反馈以改进

我的解决方案是基于我读过的关于这个问题的几篇文章。 因为对字段分隔符的定义没有限制,所以我决定使用ASCII表,除去明显的(字母数字字符)和不太明显的(不可打印的),但选项卡代码除外。使用这些值,我填充了一个字典,其中ASCII码是要用我的代码填充的值的键

然后是逐行阅读CSV,在每一行中查找字典中的关键字符,并增加我遇到的每一个字符的值。循环将继续到文件末尾,或者在本例中循环次数限制为100次。您可以根据需要进行更改,但100对于检测分隔符来说已经足够了。然后,定界符由具有最大值的字典键(ASCII码)确定

调用例程示例

private sub Main()
    dim separator As Char
    separator= separatorDetect(txtInputFile.Text)
end sub
主要检测功能

Private Function separatorDetect(ByVal StrFileName As String) As Char
    Dim i As Int16 = 0
    Dim separator As List(Of Char)
    Dim dictSeparators As New Dictionary(Of Integer, Integer)
    dictSeparators.Add(9, 0)
    dictSeparators.Add(33, 0)
    For i = 35 To 47
        dictSeparators.Add(i, 0)
    Next
    For i = 91 To 96
        dictSeparators.Add(i, 0)
    Next
    For i = 123 To 126
        dictSeparators.Add(i, 0)
    Next
    Dim lineCounter As Integer = 0
    Dim line As String = String.Empty
    Dim keyList As New List(Of Integer)
    For Each key In dictSeparators.Keys
        keyList.Add(key)
    Next
    Dim tmp As Char
    Using textReader = New StreamReader(StrFileName)
        Do Until textReader.EndOfStream
            line = textReader.ReadLine.Trim
            For Each key In keyList
                tmp = Convert.ToChar(key)
                dictSeparators.Item(key) = dictSeparators.Item(key) + InStrCount(line, tmp)
            Next
            lineCounter += 1
            If lineCounter = 99 Then GoTo readEnd
        Loop
    End Using
readEnd:
    Dim max = dictSeparators.Aggregate(Function(l, r) If(l.Value > r.Value, l, r)).Key
    Return Chr(max)
End Function
计数函数的递归索引

Private Function InStrCount(ByVal SourceString As String, ByVal SearchString As Char, _
                Optional ByRef StartPos As Integer = 0, _
                Optional ByRef Count As Integer = 0) As Integer
    If SourceString.IndexOf(SearchString, StartPos) > -1 Then
        Count += 1
        InStrCount(SourceString, SearchString, SourceString.IndexOf(SearchString, StartPos) + 1, Count)
    End If
    Return Count
End Function

这对我来说很有效,但我总是很高兴能以一种更好、更优化的方式展示给大家。

在中,我提到,这似乎是一个维护良好且受欢迎的库,它实际上提供了一个API来为您处理检测。

有趣的是,CSV代表逗号分隔的值。@om nom nom如果总是这样的话,那就太好了。但现实是different@om-nom nom:有人说C代表性格。