【问题标题】:Splitting Comma Separated Values (CSV)拆分逗号分隔值 (CSV)
【发布时间】:2010-11-06 01:26:56
【问题描述】:

如何在 c sharp 中拆分 CSV 文件?以及如何显示?

【问题讨论】:

  • 不是很精确,你的问题……如果你提供更多细节,你会得到更多有用的答案。
  • 简单地说,我的意思是我必须读取我输入的字符串,然后拆分并存储到一个数组中。
  • @Nisam:Benjol 的意思是,如果您展示字符串外观的实际示例,提供如何拆分字符串的示例会更容易。
  • 好的。我有一个名为 address.csv 的 CSV 文件(我没有代码示例),我只需要拆分文件的内容。

标签: c# csv


【解决方案1】:

问题:将逗号分隔的字符串转换为数组,其中“带引号的字符串,,”中的逗号不应被视为分隔符,而应视为条目的一部分

输入: String: First,"Second","Even,With,Commas",,Normal,"Sentence,with ""different"" problems",3,4,5

输出: String-Array: ['First','Second','Even,With,Commas','','Normal','Sentence,with "different" problems','3','4','5']

代码:

string sLine;
sLine = "First,\"Second\",\"Even,With,Commas\",,Normal,\"Sentence,with \"\"different\"\" problems\",3,4,5";

// 1. Split line by separator; do not split if separator is within quotes
string Separator = ",";
string Escape = '"'.ToString();
MatchCollection Matches = Regex.Matches(sLine,
    string.Format("({1}[^{1}]*{1})*(?<Separator>{0})({1}[^{1}]*{1})*", Separator, Escape));
string[] asColumns = new string[Matches.Count + 1];

int PriorMatchIndex = 0;
for (int Index = 0; Index <= asColumns.Length - 2; Index++)
{
    asColumns[Index] = sLine.Substring(PriorMatchIndex, Matches[Index].Groups["Separator"].Index - PriorMatchIndex);
    PriorMatchIndex = Matches[Index].Groups["Separator"].Index + Separator.Length;
}
asColumns[asColumns.Length - 1] = sLine.Substring(PriorMatchIndex);

// 2. Remove quotes
for (int Index = 0; Index <= asColumns.Length - 1; Index++)
{
    if (Regex.IsMatch(asColumns[Index], string.Format("^{0}[^{0}].*[^{0}]{0}$", Escape))) // If "Text" is sourrounded by quotes (but ignore double quotes => "Leave ""inside"" quotes")
    {
        asColumns[Index] = asColumns[Index].Substring(1, asColumns[Index].Length - 2); // "Text" => Text
    }
    asColumns[Index] = asColumns[Index].Replace(Escape + Escape, Escape); // Remove double quotes ('My ""special"" text' => 'My "special" text')
    if (asColumns[Index] == null) asColumns[Index] = "";
}

输出数组为asColumns

【讨论】:

    【解决方案2】:

    我得到了查询的结果。就像我使用 io.file 读取文件一样简单。并且所有文本都存储在一个字符串中。之后我用分隔符分开了。代码如下所示。

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace CSV
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                string csv = "user1, user2, user3,user4,user5";
    
                string[] split = csv.Split(new char[] {',',' '});
                foreach(string s in split)
                {
                    if (s.Trim() != "")
                        Console.WriteLine(s);
                }
                Console.ReadLine();
            }
        }
    }
    

    【讨论】:

    • 很高兴您找到了解决方案。如果您需要更深入地查看 CSV 文件,您可能需要查看此处发布的其他一些方法和链接。您似乎知道 CSV 将采用的确切格式。另外,请考虑文件大小。代表整个 CSV 的字符串最多可以达到几兆字节,但如果您正在处理大文件,请查看 Vinko 发布的 Codeproject 链接。即使您不需要在此示例中使用它们,您也应该确保您了解 StringSplitOptions 和 String.Split 的“count”参数的作用。 :-)
    【解决方案3】:

    导入 Micorosoft.VisualBasic 作为参考(我知道,它还不错)并使用 Microsoft.VisualBasic.FileIO.TextFieldParser - 这可以很好地处理 CSV 文件,并且可以在任何 .Net 语言中使用。

    【讨论】:

      【解决方案4】:

      以下函数从 CSV 文件中取出一行并将其拆分为 List&lt;string&gt;

      参数:
      string line = 要拆分的行
      string textQualifier = 什么(如果有)文本限定符(即“”或“\””或“'”)
      char delim = 字段分隔符(即 ',' 或 ';' 或 '|' 或 '\t')
      int colCount = 预期的字段数(0 表示不检查)

      示例用法:

      List<string> fields = SplitLine(line, "\"", ',', 5);
      // or
      List<string> fields = SplitLine(line, "'", '|', 10);
      // or
      List<string> fields = SplitLine(line, "", '\t', 0);
      

      功能:

      private List<string> SplitLine(string line, string textQualifier, char delim, int colCount)
      {
          List<string> fields = new List<string>();
          string origLine = line;
      
          char textQual = '"';
          bool hasTextQual = false;
          if (!String.IsNullOrEmpty(textQualifier))
          {
              hasTextQual = true;
              textQual = textQualifier[0];            
          }
      
          if (hasTextQual)
          {
              while (!String.IsNullOrEmpty(line))
              {
                  if (line[0] == textQual) // field is text qualified so look for next unqualified delimiter
                  {
                      int fieldLen = 1;
                      while (true)
                      {
                          if (line.Length == 2) // must be final field (zero length)
                          {
                              fieldLen = 2;
                              break;
                          }
                          else if (fieldLen + 1 >= line.Length) // must be final field
                          {
                              fieldLen += 1;
                              break;
                          }
                          else if (line[fieldLen] == textQual && line[fieldLen + 1] == textQual) // escaped text qualifier
                          {
                              fieldLen += 2;
                          }
                          else if (line[fieldLen] == textQual && line[fieldLen + 1] == delim) // must be end of field
                          {
                              fieldLen += 1;
                              break;
                          }
                          else // not a delimiter
                          {
                              fieldLen += 1;
                          }
                      }
                      string escapedQual = textQual.ToString() + textQual.ToString();
                      fields.Add(line.Substring(1, fieldLen - 2).Replace(escapedQual, textQual.ToString())); // replace escaped qualifiers
                      if (line.Length >= fieldLen + 1)
                      {
                          line = line.Substring(fieldLen + 1);
                          if (line == "") // blank final field
                          {
                              fields.Add("");
                          }
                      }
                      else
                      {
                          line = "";
                      }
                  }
                  else // field is not text qualified
                  {
                      int fieldLen = line.IndexOf(delim);
                      if (fieldLen != -1) // check next delimiter position
                      {
                          fields.Add(line.Substring(0, fieldLen));
                          line = line.Substring(fieldLen + 1);
                          if (line == "") // final field must be blank 
                          {
                              fields.Add("");
                          }
                      }
                      else // must be last field
                      {
                          fields.Add(line);
                          line = "";
                      }
                  }
              }
          }
          else // if there is no text qualifier, then use existing split function
          {
              fields.AddRange(line.Split(delim));
          }      
      
          if (colCount > 0 && colCount != fields.Count) // count doesn't match expected so throw exception
          {
              throw new Exception("Field count was:" + fields.Count.ToString() + ", expected:" + colCount.ToString() + ". Line:" + origLine);
      
          }
          return fields;
      }
      

      【讨论】:

        【解决方案5】:

        我一直在 Microsoft.VisualBasic.FileIO 命名空间中为我正在处理的 C# 项目使用 TextFieldParser Class。它将处理复杂的问题,例如嵌入逗号或括在引号中的字段等。它返回一个字符串[],除了 CSV 文件之外,还可以用于解析几乎任何类型的结构化文本文件。

        【讨论】:

        • 有趣。我以前从没看过这里。我最近用 C# 编写了一个完整的 CSV 类,这会有所帮助。我最终将换行符转换为〜,而且逗号只能出现在最后一个字段中,所以我使用 String.Split 的 maxentries 参数来捕获整个最后一个字段,逗号和所有,但我必须看看在这堂课上。感谢您的链接。
        • “通用”功能的订购 1) 核心框架 2) 扩展框架 3) 开源库 4) 廉价付费库 5) 自己编写
        【解决方案6】:

        这是我偶尔使用的 CSV 解析器。

        用法:(dgvMyView 是一种数据网格类型。)

        CSVReader reader = new CSVReader("C:\MyFile.txt");
        reader.DisplayResults(dgvMyView);
        

        类:

        using System.IO;
        using System.Text.RegularExpressions;
        using System.Windows.Forms;    
        public class CSVReader
        {
            private const string ESCAPE_SPLIT_REGEX = "({1}[^{1}]*{1})*(?<Separator>{0})({1}[^{1}]*{1})*";
            private string[] FieldNames;
            private List<string[]> Records;
            private int ReadIndex;
        
            public CSVReader(string File)
            {
                Records = new List<string[]>();
                string[] Record = null;
                StreamReader Reader = new StreamReader(File);
                int Index = 0;
                bool BlankRecord = true;
        
                FieldNames = GetEscapedSVs(Reader.ReadLine());
                while (!Reader.EndOfStream)
                {
                    Record = GetEscapedSVs(Reader.ReadLine());
                    BlankRecord = true;
                    for (Index = 0; Index <= Record.Length - 1; Index++)
                    {
                        if (!string.IsNullOrEmpty(Record[Index])) BlankRecord = false;
                    }
                    if (!BlankRecord) Records.Add(Record);
                }
                ReadIndex = -1;
                Reader.Close();
            }
        
            private string[] GetEscapedSVs(string Data)
            {
                return GetEscapedSVs(Data, ",", "\"");
            }
            private string[] GetEscapedSVs(string Data, string Separator, string Escape)
            {
                string[] Result = null;
                int Index = 0;
                int PriorMatchIndex = 0;
                MatchCollection Matches = Regex.Matches(Data, string.Format(ESCAPE_SPLIT_REGEX, Separator, Escape));
        
                Result = new string[Matches.Count];
        
        
                for (Index = 0; Index <= Result.Length - 2; Index++)
                {
                    Result[Index] = Data.Substring(PriorMatchIndex, Matches[Index].Groups["Separator"].Index - PriorMatchIndex);
                    PriorMatchIndex = Matches[Index].Groups["Separator"].Index + Separator.Length;
                }
                Result[Result.Length - 1] = Data.Substring(PriorMatchIndex);
        
                for (Index = 0; Index <= Result.Length - 1; Index++)
                {
                    if (Regex.IsMatch(Result[Index], string.Format("^{0}[^{0}].*[^{0}]{0}$", Escape))) Result[Index] = Result[Index].Substring(1, Result[Index].Length - 2);
                    Result[Index] = Result[Index].Replace(Escape + Escape, Escape);
                    if (Result[Index] == null) Result[Index] = "";
                }
        
                return Result;
            }
        
            public int FieldCount
            {
                get { return FieldNames.Length; }
            }
        
            public string GetString(int Index)
            {
                return Records[ReadIndex][Index];
            }
        
            public string GetName(int Index)
            {
                return FieldNames[Index];
            }
        
            public bool Read()
            {
                ReadIndex = ReadIndex + 1;
                return ReadIndex < Records.Count;
            }
        
        
            public void DisplayResults(DataGridView DataView)
            {
                DataGridViewColumn col = default(DataGridViewColumn);
                DataGridViewRow row = default(DataGridViewRow);
                DataGridViewCell cell = default(DataGridViewCell);
                DataGridViewColumnHeaderCell header = default(DataGridViewColumnHeaderCell);
                int Index = 0;
                ReadIndex = -1;
        
                DataView.Rows.Clear();
                DataView.Columns.Clear();
        
                for (Index = 0; Index <= FieldCount - 1; Index++)
                {
                    col = new DataGridViewColumn();
                    col.CellTemplate = new DataGridViewTextBoxCell();
                    header = new DataGridViewColumnHeaderCell();
                    header.Value = GetName(Index);
                    col.HeaderCell = header;
                    DataView.Columns.Add(col);
                }
        
                while (Read())
                {
                    row = new DataGridViewRow();
                    for (Index = 0; Index <= FieldCount - 1; Index++)
                    {
                        cell = new DataGridViewTextBoxCell();
                        cell.Value = GetString(Index).ToString();
                        row.Cells.Add(cell);
                    }
                    DataView.Rows.Add(row);
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          显示在哪里?关于拆分,最好的方法是使用一个好的库来实现。

          This library很不错,真心推荐。

          使用幼稚方法的问题是,通常会失败,有很多考虑因素,甚至没有考虑性能:

          • 如果文本包含逗号怎么办
          • 支持多种现有格式(以分号分隔,或用引号括起来的文本,或单引号等)
          • 还有许多其他

          【讨论】:

            【解决方案8】:

            一次读取一行文件,然后...

            foreach (String line in line.Split(new char[] { ',' }))
                Console.WriteLine(line);
            

            【讨论】:

            • 不幸的是,如果值嵌入了逗号或字段用引号括起来,这将不起作用。请改用 TextFieldParser 类。
            • 是的,我在提供此示例后不久就意识到了这一点>.
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-25
            • 2011-07-26
            • 2015-04-01
            相关资源
            最近更新 更多