我如何解析c#中的文本文件

时间:2008-11-19 00:37:18

标签: c# parsing text-files

如何解析c#中的文本文件?

10 个答案:

答案 0 :(得分:8)

检查这个有趣的方法,Linq To Text Files,非常好,你只需要一个IEnumerable<string>方法,每个file.ReadLine()产生一次,你就可以进行查询。

Here是另一篇更好地解释相同技术的文章。

答案 1 :(得分:5)

using (TextReader rdr = new StreamReader(fullFilePath))
{
  string line;

  while ((line = rdr.ReadLine()) != null)
  {
    // use line here
  }
}

将变量“fullFilePath”设置为完整路径,例如。 C:\ TEMP \ myTextFile.txt

答案 2 :(得分:3)

算法可能如下所示:

  1. 打开文本文件
  2. 对于文件中的每一行:
  3. Parse Line
  4. 解析一条线有几种方法。

    从初学者角度来看,最简单的方法是使用String方法。

    System.String at MSDN

    如果您需要更多挑战,那么您可以使用System.Text.RegularExpression库来解析您的文本。

    RegEx at MSDN

答案 3 :(得分:1)

您可能希望使用辅助类,例如http://www.blackbeltcoder.com/Articles/strings/a-text-parsing-helper-class中描述的辅助类。

答案 4 :(得分:1)

通过多年分析CSV文件,包括破损或有边缘情况的文件,这里的代码几乎可以通过我的所有单元测试:

/// <summary>
/// Read in a line of text, and use the Add() function to add these items to the current CSV structure
/// </summary>
/// <param name="s"></param>
public static bool TryParseCSVLine(string s, char delimiter, char text_qualifier, out string[] array)
{
    bool success = true;
    List<string> list = new List<string>();
    StringBuilder work = new StringBuilder();
    for (int i = 0; i < s.Length; i++) {
        char c = s[i];

        // If we are starting a new field, is this field text qualified?
        if ((c == text_qualifier) && (work.Length == 0)) {
            int p2;
            while (true) {
                p2 = s.IndexOf(text_qualifier, i + 1);

                // for some reason, this text qualifier is broken
                if (p2 < 0) {
                    work.Append(s.Substring(i + 1));
                    i = s.Length;
                    success = false;
                    break;
                }

                // Append this qualified string
                work.Append(s.Substring(i + 1, p2 - i - 1));
                i = p2;

                // If this is a double quote, keep going!
                if (((p2 + 1) < s.Length) && (s[p2 + 1] == text_qualifier)) {
                    work.Append(text_qualifier);
                    i++;

                    // otherwise, this is a single qualifier, we're done
                } else {
                    break;
                }
            }

            // Does this start a new field?
        } else if (c == delimiter) {
            list.Add(work.ToString());
            work.Length = 0;

            // Test for special case: when the user has written a casual comma, space, and text qualifier, skip the space
            // Checks if the second parameter of the if statement will pass through successfully
            // e.g. "bob", "mary", "bill"
            if (i + 2 <= s.Length - 1) {
                if (s[i + 1].Equals(' ') && s[i + 2].Equals(text_qualifier)) {
                    i++;
                }
            }
        } else {
            work.Append(c);
        }
    }
    list.Add(work.ToString());

    // If we have nothing in the list, and it's possible that this might be a tab delimited list, try that before giving up
    if (list.Count == 1 && delimiter != DEFAULT_TAB_DELIMITER) {
        string[] tab_delimited_array = ParseLine(s, DEFAULT_TAB_DELIMITER, DEFAULT_QUALIFIER);
        if (tab_delimited_array.Length > list.Count) {
            array = tab_delimited_array;
            return success;
        }
    }

    // Return the array we parsed
    array = list.ToArray();
    return success;
}

但是,此函数实际上并不解析每个有效的CSV文件!某些文件中嵌入了换行符,您需要启用流式读取器将多行扫描在一起以返回一个数组。这是一个工具:

/// <summary>
/// Parse a line whose values may include newline symbols or CR/LF
/// </summary>
/// <param name="sr"></param>
/// <returns></returns>
public static string[] ParseMultiLine(StreamReader sr, char delimiter, char text_qualifier)
{
    StringBuilder sb = new StringBuilder();
    string[] array = null;
    while (!sr.EndOfStream) {

        // Read in a line
        sb.Append(sr.ReadLine());

        // Does it parse?
        string s = sb.ToString();
        if (TryParseCSVLine(s, delimiter, text_qualifier, out array)) {
            return array;
        }
    }

    // Fails to parse - return the best array we were able to get
    return array;
}

作为参考,我放置了open source CSV code on code.google.com

答案 5 :(得分:0)

如果您使用的不仅仅是一种简单的语言,请使用解析器生成器。它驱动了 me 坚果,但我听说过ANTLR的好东西(注意:在开始之前先阅读手册并阅读它。如果你之前使用过它以外的解析器生成器没有正确接近它,至少我没有)

还存在其他工具。

答案 6 :(得分:0)

如果不知道你所处的文本文件是什么类型,很难回答。但是,FileHelpers库有一套广泛的工具来帮助定长文件格式,多记录,分隔等。

答案 7 :(得分:0)

你是什么意思解析?解析通常意味着将输入拆分为令牌,如果您尝试实现编程语言,则可以执行此操作。如果您只是想阅读文本文件的内容,请查看System.IO.FileInfo。

答案 8 :(得分:0)

Pero答案的一个小改进:

FileInfo txtFile = new FileInfo("c:\myfile.txt");
if(!txtFile.Exists) { // error handling }

using (TextReader rdr = txtFile.OpenText())
{
     // use the text file as Pero suggested
}

FileInfo类使您有机会在实际开始阅读之前对文件“执行操作”。您还可以在函数之间传递它作为文件位置的更好抽象(而不是使用完整路径字符串)。 FileInfo规范化路径,因此它绝对正确(例如,在适当的情况下转入/进入\),并允许您提取有关文件的额外数据 - 父目录,扩展名,仅限名称,权限等。

答案 9 :(得分:0)

首先,请确保您具有以下命名空间:

using System.Data;
using System.IO;
using System.Text.RegularExpressions;

接下来,我们构建一个函数,将任何CSV输入字符串解析为DataTable:

public DataTable ParseCSV(string inputString) {

  DataTable dt=new DataTable();

  // declare the Regular Expression that will match versus the input string
  Regex re=new Regex("((?<field>[^\",\\r\\n]+)|\"(?<field>([^\"]|\"\")+)\")(,|(?<rowbreak>\\r\\n|\\n|$))");

  ArrayList colArray=new ArrayList();
  ArrayList rowArray=new ArrayList();

  int colCount=0;
  int maxColCount=0;
  string rowbreak="";
  string field="";

  MatchCollection mc=re.Matches(inputString);

  foreach(Match m in mc) {

    // retrieve the field and replace two double-quotes with a single double-quote
    field=m.Result("${field}").Replace("\"\"","\"");

    rowbreak=m.Result("${rowbreak}");

    if (field.Length > 0) {
      colArray.Add(field);                  
      colCount++;
    }

    if (rowbreak.Length > 0) {

      // add the column array to the row Array List
      rowArray.Add(colArray.ToArray());

      // create a new Array List to hold the field values
      colArray=new ArrayList(); 

      if (colCount > maxColCount)
        maxColCount=colCount;

      colCount=0;
    }
  }

  if (rowbreak.Length == 0) {
    // this is executed when the last line doesn't
    // end with a line break
    rowArray.Add(colArray.ToArray());
    if (colCount > maxColCount)
      maxColCount=colCount;
  }

  // create the columns for the table
  for(int i=0; i < maxColCount; i++)
  dt.Columns.Add(String.Format("col{0:000}",i));

  // convert the row Array List into an Array object for easier access
  Array ra=rowArray.ToArray();
  for(int i=0; i < ra.Length; i++) {                

    // create a new DataRow
    DataRow dr=dt.NewRow();

    // convert the column Array List into an Array object for easier access
    Array ca=(Array)(ra.GetValue(i));               

    // add each field into the new DataRow
    for(int j=0; j < ca.Length; j++)
      dr[j]=ca.GetValue(j);

    // add the new DataRow to the DataTable
    dt.Rows.Add(dr);
  }

  // in case no data was parsed, create a single column
  if (dt.Columns.Count == 0)
    dt.Columns.Add("NoData");

  return dt;
}

现在我们有一个用于将字符串转换为DataTable的解析器,我们现在需要的是一个从CSV文件中读取内容并将其传递给ParseCSV函数的函数:

public DataTable ParseCSVFile(string path) {

  string inputString="";

  // check that the file exists before opening it
  if (File.Exists(path)) {

    StreamReader sr = new StreamReader(path);
    inputString = sr.ReadToEnd();
    sr.Close();

  }

  return ParseCSV(inputString);
}

现在,您可以使用CSV文件中的数据轻松填充DataGrid:

protected System.Web.UI.WebControls.DataGrid DataGrid1;

private void Page_Load(object sender, System.EventArgs e) {

  // call the parser
  DataTable dt=ParseCSVFile(Server.MapPath("./demo.csv"));          

  // bind the resulting DataTable to a DataGrid Web Control
  DataGrid1.DataSource=dt;
  DataGrid1.DataBind();
}

恭喜!您现在可以将CSV解析为DataTable。祝你的节目顺利。