C# 在c中查找csv或文本文件的分隔符#

C# 在c中查找csv或文本文件的分隔符#,c#,csv,C#,Csv,我想找到一个分隔符,用于分隔csv或文本文件中的列 我正在使用TextFieldParser类来读取这些文件 下面是我的代码 String path = @"c:\abc.csv"; DataTable dt = new DataTable(); if (File.Exists(path)) { using (Microsoft.VisualBasic.FileIO.TextFieldParser parser = new Microsoft.VisualBasic.FileIO.Tex

我想找到一个分隔符,用于分隔csv或文本文件中的列

我正在使用TextFieldParser类来读取这些文件

下面是我的代码

String path = @"c:\abc.csv";
DataTable dt = new DataTable();
if (File.Exists(path))
{
    using (Microsoft.VisualBasic.FileIO.TextFieldParser parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(path))
    {
        parser.TextFieldType = FieldType.Delimited;
        if (path.Contains(".txt"))
        {       
            parser.SetDelimiters("|");
        }
        else
        {
            parser.SetDelimiters(",");
        }
        parser.HasFieldsEnclosedInQuotes = true;
        bool firstLine = true;
        while (!parser.EndOfData)
        {
            string[] fields = parser.ReadFields();
            if (firstLine)
            {
                  foreach (var val in fields)
                  {
                      dt.Columns.Add(val);
                  }
                  firstLine = false;
                  continue;
             }
             dt.Rows.Add(fields);
          }
     }
 lblCount.Text = "Count of total rows in the file: " + dt.Rows.Count.ToString();
 dgvTextFieldParser1.DataSource = dt;
我希望从文件中读取分隔符,然后传递它,而不是根据文件类型手动传递分隔符


我该怎么做呢?

数学上是正确的,但毫无用处。答案:这是不可能的

实用的回答:这是可能的,但取决于你对文件结构的了解程度。它归结为一系列假设,根据我们所做的假设,答案会有所不同。如果你不能做出任何假设,那么。。。请看数学上正确的答案

例如,我们可以假设分隔符是下面集合中的一个或任意一个元素吗

List<char> delimiters = new List<char>{' ', ';', '|'};
List delimiters=新列表{“”,“;”,“|”};
或者我们可以假设分隔符产生的元素长度相等吗

我们应该试着找到一个单一字符的分隔符,还是一个单词可以是一个

等等

基于这个问题,我将假设这是第一个选项,并且我们有一组有限的可能字符,其中恰好有一个是给定文件的分隔符

你数一数每一个这样的角色出现的次数,并假设出现频率最高的就是那个?这是否足够严格,或者你需要更确定吗

List<char> delimiters = new List<char>{' ', ';', '-'};
Dictionary<char, int> counts = delimiters.ToDictionary(key => key, value => 0);
foreach(char c in delimiters)
  counts[c] = textArray.Count(t => t == c);
List delimiters=新列表{',';','-'};
字典计数=分隔符。ToDictionary(key=>key,value=>0);
foreach(分隔符中的字符c)
counts[c]=textArray.Count(t=>t==c);
我不在计算机前,因此无法验证,但最后一步是从字典返回键,该键的值为最大值


您需要考虑一种特殊情况,即没有检测到分隔符,两种类型的分隔符数量相等等等。

您可能需要从文件中提取n个字节,使用哈希映射/字典计算可能的分隔符字符(或找到的所有字符),然后重复最多的字符可能就是您要查找的分隔符。对我来说,用作分隔符的字符将是使用最多的字符,这是有道理的。当您重置流时,由于您使用的是文本读取器,您可能需要初始化另一个文本读取器或其他东西。如果CSV使用了多个分隔符,那么这将变得更加复杂。您可能必须忽略一些字符,如字母和数字

使用LINQ的非常简单的猜测方法:

static class CsvSeperatorDetector
{
    private static readonly char[] SeparatorChars = {';', '|', '\t', ','};

    public static char DetectSeparator(string csvFilePath)
    {
        string[] lines = File.ReadAllLines(csvFilePath);
        return DetectSeparator(lines);
    }

    public static char DetectSeparator(string[] lines)
    {
        var q = SeparatorChars.Select(sep => new
                {Separator = sep, Found = lines.GroupBy(line => line.Count(ch => ch == sep))})
            .OrderByDescending(res => res.Found.Count(grp => grp.Key > 0))
            .ThenBy(res => res.Found.Count())
            .First();

        return q.Separator;
    }
}
这样做的目的是逐行读取文件(请注意,CSV文件可能包含换行符),然后检查每个潜在分隔符在每行中出现的频率。 然后,我们检查在大多数行上出现的分隔符,在相同行数上出现的分隔符中,我们选择分布最均匀的分隔符(例如,每行5个分隔符的排名高于在一行中出现一次,在另一行中出现10次的分隔符)。
当然,为了自己的目的,您可能需要对此进行调整,添加错误处理、回退逻辑等等。我确信它并不完美,但对我来说已经足够好了。

除了文件扩展名之外,你怎么知道分隔符是什么字符?你能数一数每个字符的实例,并假设最常见的一个是分隔符吗?这只是我用来读取两个文件的一个例子。我想做的是自动检测分隔符(不是基于文件类型,而是通过读取数据)。@Henry如果文件中有带引号(“”)的数据,那么最常见的是引号,而不是分隔符。如果假定的分隔符字符在引号内,您可以使用Henry的方法并进行例外(例如,使用RegEx)。我会找到的常见分隔符是一组列表分隔符=新列表{“”,“;”,“-”,“|',”,“}@AMeh我认为这个想法是,大多数分隔格式对字段内容中出现的其他分隔符没有限制,因此,例如,您可以使用
在字段中用
|
分隔的文本,所有文本都将被检测到。你可以尝试根据频率提出一些启发,但如果没有额外的信息,我不确定你是否能确定。你能详细说明一下为什么需要自动检测它吗?数据源不能提供额外的存储信息吗?@ryachza我正在textfieldparser类上运行一个测试,以读取不同类型的文件并在datagrid中显示数据。为了提高性能,我希望尽可能地自动化该过程,因此,如果我想在将来读取多个不同类型的文件,我可以很容易地做到这一点,而无需花费太多精力来计算每个文件的分隔符。@AMeh我不确定我是否理解您所说的“为了性能”的含义-您试图优化什么?关于读取不同的文件类型-您从哪里获取正在读取的数据?我希望您的解析器对(格式、数据)对进行操作,而不是在每次读取数据时都尝试重新检测格式?@ryachza我猜OP希望呈现数据,并且需要一些便利,以便更容易地对读取的文件进行定界。因此,优化不是在算法方面,而是不需要手动调查文件(可能就是这样)。他的意思可能是自动化,而不是优化。