【问题标题】:How to create a generic text file parser for any find of text file?如何为任何文本文件的查找创建通用文本文件解析器?
【发布时间】:2014-03-22 12:21:29
【问题描述】:

想在 c# 中为任何文本文件的查找创建一个通用的文本文件解析器。实际上我有 4 个应用程序,所有 4 个从 txt 文件格式获取输入数据,但文本文件本质上不是同质的。我已经尝试了 fixwithdelemition。

private static DataTable FixedWidthDiliminatedTxtRead()
{
    string[] fields;
    StringBuilder sb = new StringBuilder();
    List<StringBuilder> lst = new List<StringBuilder>();
    DataTable dtable = new DataTable();
    ArrayList aList;

    using (TextFieldParser tfp = new TextFieldParser(testOCC))
    {
        tfp.TextFieldType = FieldType.FixedWidth;
        tfp.SetFieldWidths(new int[12] { 2,25,8,12,13,5,6,3,10,11,10,24 });
        for (int col = 1; col < 13; ++col)
            dtable.Columns.Add("COL" + col);
        while (!tfp.EndOfData)
        {
            fields = tfp.ReadFields();
            aList = new ArrayList();
            for (int i = 0; i < fields.Length; ++i)
                aList.Add(fields[i] as string);
            if (dtable.Columns.Count == aList.Count)

            dtable.Rows.Add(aList.ToArray());


        }
    }
    return dtable;
}

但我觉得它非常僵化,并且确实因应用程序而异,使其可配置。任何更好的方式..

tfp.SetFieldWidths(new int[12] { 2,25,8,12,13,5,6,3,10,11,10,24 });

文件性质: 它是一种报告类型的文件。 列的位置非常相似 文件id不同的行数据。

我把这个作为参考

http://www.codeproject.com/Articles/11698/A-Portable-and-Efficient-Generic-Parser-for-Flat-F

还有其他想法吗?

【问题讨论】:

  • 感谢编辑 :)
  • 不是我的领域,但我猜如果你有 4 种不同的 txt 格式,你可以有 4 个不同的 int 数组来输入 tfp.SetFieldWidths()。也许您应该编写一个例程,找出您正在处理的 4 种文本类型中的哪一种,然后调用 FixedWidthDiliminatedTxtRead 传递一个 int[] 参数,其中列号和长度已经定义...
  • 您可以使用 CSV 解析器组件,而不是自己编写代码。有关一些选项,请参阅stackoverflow.com/questions/316649/csv-parsing
  • 看看 FileHelpers 库 - filehelpers.com。即使您不想使用它,它也是一个已经存在多年的可靠库,您可以从中获得一些好主意。

标签: c# asp.net .net generics text-parsing


【解决方案1】:

如果唯一不同的是字段宽度,您可以尝试将字段宽度作为参数发送:

private static DataTable FixedWidthDiliminatedTxtRead(int[] fieldWidthArray)
{
    string[] fields;
    StringBuilder sb = new StringBuilder();
    List<StringBuilder> lst = new List<StringBuilder>();
    DataTable dtable = new DataTable();
    ArrayList aList;

    using (TextFieldParser tfp = new TextFieldParser(testOCC))
    {
        tfp.TextFieldType = FieldType.FixedWidth;
        tfp.SetFieldWidths(fieldWidthArray);
        for (int col = 1; col < 13; ++col)
            dtable.Columns.Add("COL" + col);
        while (!tfp.EndOfData)
        {
            fields = tfp.ReadFields();
            aList = new ArrayList();
            for (int i = 0; i < fields.Length; ++i)
                aList.Add(fields[i] as string);
            if (dtable.Columns.Count == aList.Count)

            dtable.Rows.Add(aList.ToArray());


        }
    }
    return dtable;
}

如果您有更多的逻辑来获取数据,您可能需要考虑为GenericTextParser 定义一个接口或抽象类,并为每个其他文件创建具体实现。

【讨论】:

    【解决方案2】:
    private static DataTable FixedWidthTxtRead(string filename, int[] fieldWidths)
    {
        string[] fields;
        DataTable dtable = new DataTable();
        ArrayList aList;
        using (TextFieldParser tfp = new TextFieldParser(filename))
        {
            tfp.TextFieldType = FieldType.FixedWidth;
            tfp.SetFieldWidths(fieldWidths);
            for (int col = 1; col <= fieldWidths.length; ++col)
                dtable.Columns.Add("COL" + col);
            while (!tfp.EndOfData)
            {
                fields = tfp.ReadFields();
                aList = new ArrayList();
                for (int i = 0; i < fields.Length; ++i)
                    aList.Add(fields[i] as string);
                if (dtable.Columns.Count == aList.Count) dtable.Rows.Add(aList.ToArray());
            }
        }
        return dtable;
    }
    

    【讨论】:

      【解决方案3】:

      嘿,我上周做了一个。

      我写它的目的不是为了其他人使用它,所以如果它没有很好地记录,我提前道歉,但我为你清理了它。此外,我从堆栈溢出中抓取了几段代码,所以我不是其中几段的原作者。

      您需要编辑的地方是路径和路径输出以及文本的分隔符。 字符 [] 分隔符 = 新字符 []

      所以它会搜索一个单词的一部分,然后抓取整个单词。为此,我使用了一个 c# 控制台应用程序。

      给你:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      using System.IO;
      
      namespace UniqueListofStringFinder
      {
          class Program
          {
              static void Main(string[] args)
              {
                  string path = @"c:\Your Path\in.txt";
                  string pathOut = @"c:\Your Path\out.txt";
                  string data = "!";
      
                  Console.WriteLine("Current Path In is set to: " + path);
                  Console.WriteLine("Current Path Out is set to: " + pathOut);
                  Console.WriteLine(Environment.NewLine + Environment.NewLine + "Input String to Search For:");
                  Console.Read();
                  string input = Console.ReadLine();            
      
                  // Delete the file if it exists. 
                  if (!File.Exists(path))
                  {
                      // Create the file. 
                      using (FileStream fs = File.Create(path))
                      {
                          Byte[] info =
                              new UTF8Encoding(true).GetBytes("This is some text in the file.");
      
                          // Add some information to the file.
                          fs.Write(info, 0, info.Length);
                      }
                  }
      
                  System.IO.StreamReader file = new System.IO.StreamReader(path);
                  List<string> Spec = new List<string>();
      
                  using (StreamReader sr = File.OpenText(path))
                  {
                      while (!file.EndOfStream)
                      {
                          string s = file.ReadLine();
                          if (s.Contains(input))
                          {                            
                              char[] delimiters = new char[] { '\r', '\n', '\t', ')', '(', ',', '=', '"', '\'', '<', '>', '$', ' ', '@', '[', ']' };
                              string[] parts = s.Split(delimiters,
                                               StringSplitOptions.RemoveEmptyEntries);
      
                              foreach (string word in parts)
                              {
                                  if (word.Contains(input))
                                  {                                   
                                      if( word.IndexOf(input) == 0)
                                      {
                                          Spec.Add(word);
                                      }
                                  }
                              }                            
                          }
                      }
      
      
                      Spec.Sort();
      
                      // Open the stream and read it back. 
      
                      //while ((s = sr.ReadLine()) != null)
                      //{
                      //    Console.WriteLine(s);
                      //}
                  }
                  Console.WriteLine();
      
                  StringBuilder builder = new StringBuilder();
                  foreach (string s in Spec) // Loop through all strings
                  {
                      builder.Append(s).Append(Environment.NewLine); // Append string to StringBuilder
                  }
                  string result = builder.ToString(); // Get string from StringBuilder
      
      
                  Program a = new Program();
      
                  data = a.uniqueness(result);
      
                  int i = a.writeFile(data,pathOut);
      
              }
      
              public string uniqueness(string rawData )
              {
                  if (rawData == "")
                  {
                      return "Empty Data Set";
                  }
      
                  List<string> dataVar = new List<string>();  
                  List<string> holdData = new List<string>();
      
                  bool testBool = false;
                  using (StringReader reader = new StringReader(rawData))
                  {
                      string line;
                      while ((line = reader.ReadLine()) != null)
                      {    
      
                          foreach (string s in holdData)
                          {
                              if (line == s)
                              {
                                  testBool = true;
                              }
                          }
                          if (testBool == false)
                          {
                              holdData.Add(line);
                          }
                          testBool = false;
                          // Do something with the line
                      }
                  }    
      
                  int i = 0;
                  string dataOut = "";
                  foreach (string s in holdData)
                  {                   
                      dataOut += s + "\r\n";
                      i++;
                  }
      
                  // Write the string to a file.
                  return dataOut;
              }
      
              public int writeFile(string dataOut, string pathOut)
              {
                  try
                  {
                      System.IO.StreamWriter file = new System.IO.StreamWriter(pathOut);
                      file.WriteLine(dataOut);
      
                      file.Close();
                  }
                  catch (Exception ex)
                  {
                      dataOut += ex.ToString();
                      return 1;
                  }
                  return 0;
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        这是我所做的: 我为所需的处理器类型(基于文件类型/格式)构建了一个工厂,它抽象了文件阅读器。 然后,我构建了一个集合对象,其中包含我感兴趣的每个字段的一组触发器(还包含该字段指定的属性名称)。这个设置集合是通过 XML 配置文件加载的,所以我只需要更改设置,基本解析过程可以对设置的配置方式做出反应。最后,我构建了一个反射包装器,其中一旦解析了一个字段,就会设置模型对象上的相应属性。
        随着文件的流动,每个设置的触发器都会评估每个行的值。当它找到要查找的内容(通过模式匹配或列长度值)时,它会触发并冒泡并在模型对象上设置属性的事件。如果你有兴趣,我可以展示一些伪代码。为了效率,它需要一些工作,但我喜欢这个概念。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-28
          • 2014-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-23
          • 1970-01-01
          • 2010-10-25
          相关资源
          最近更新 更多