【问题标题】:How to extract specfic data from lines in a text file and output to a new text file using C#如何从文本文件中的行中提取特定数据并使用 C# 输出到新的文本文件
【发布时间】:2015-06-17 20:37:32
【问题描述】:

我有几个包含数据行的大型 .csv 文件。我需要从每一行中只提取数据的特定部分,从而忽略我不感兴趣的部分并将结果输出到一个新的文本文件中。

例如,下面是一段数据:

Fr 23:59:59 M40 N04161K RX LAG 2 JNYT  17 STORE OCC 1 PRUD 1 RAW  -9 LAG   0

Fr 23:59:59 M08  N09461M  %SAT   3  %CONG   0  MQ 0  EB 0  OSQ     0 NSQ     4

Fr 23:59:59 M20 N09461M SAT   3%  SQ     0  FLOW     4  GN  13  STOC  9

我希望编写一个如下所示的新文件:

5,23,59,59,2,17,1,1,-9,0

5,23,59,59,3,0,0,0,0,4

5,23,59,59,3,0,4,13,9

(您会注意到数据的开头是“5”,我也想用它来代替代表“星期五”的“Fr”)

数据在数据集中由“M”引用(M40、M08 等)标识,输出其数据集中的所有数据会很有用(例如,所有带有 M40 的数据都过滤到一个 .txt 文件中,因此我的'if'语句)

我希望每个数字都用逗号分隔,但不是必需的

到目前为止,这是我的代码:

class Program
{
    static void Main(string[] args)
    {
        String line;
        try
        {
            //Pass the file path and file name to the StreamReader constructor
            StreamReader sr = new StreamReader("C:\\MessExport_20110402_0000.csv");
            StreamWriter sw = new StreamWriter("C:\\output.txt");
            //Read the first line of text
            line = sr.ReadLine();

            //Continue to read until you reach end of file
            while (line != null)
            {
                if (line.Contains("M40"))
                {
                    sw.WriteLine(line);
                }
                    if (line.Contains("M08"))
                    {
                        sw.WriteLine(line);
                    }      
                line = sr.ReadLine();
            }

            //close the files
            sr.Close();
            sw.Close();
            //Console.ReadLine();
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: " + e.Message);
        }
        finally
        {
            Console.WriteLine("Executing finally block.");
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }


    }
}

然后读取下一个 .csv 文件并将结果再次输出到新的 .txt 文件会很有用

我对使用任何带有正则表达式和拆分的代码非常陌生,因此非常感谢任何帮助。

【问题讨论】:

  • 您是否尝试过自己实际拆分代码,或者这就是您拥有的所有相关代码? Also, split is a relatively easy method, even if you're new. I would give it a read over since it should accomplish what you're looking for. 在我看来,弄乱正则表达式会更令人困惑,特别是如果您不掌握 split 等基本字符串函数。
  • 我建议你检查 LastIndexOf() 方法,SubString() 方法并添加几个 ifs 以便处理数据。我认为这是一个制表符分隔的值,所以你应该开始认为你必须解析每一行,并且由于每一行都有相同数量的列,所以忽略特定的子字符串。
  • 最有意义的是使用string.SplitTryParse 函数将每条记录转换为记录类的新实例。然后,此类将包含有意义的数据表示,其中变量名称表示每个数据字段。然后,您可以轻松地使用 LINQ 随意选择和分组记录。然后,您所需要的只是一个获取元素集合并将它们写入文件的方法。使用这些组件,您应该能够构建结构良好且可重复使用的代码来操作您的数据。
  • 感谢 cmets,非常有用。我最初有一个使用 Matlab 的解决方案,但是代码需要很长时间才能执行并且不可行,因为我有几百万行数据要提取。所以我想试试看 C# 是否提供了更高效的解决方案
  • 我的计划可能不适用于大量数据,因为它涉及在写入文件之前将整个数据集存储在内存中。对于这种情况,您最好单独处理记录而不存储任何中间表示。

标签: c# regex split


【解决方案1】:

只是一个简单的实现:

string workingDirectory = @"c:\";

var days = new[] { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" };
var writers = new Dictionary<string, StreamWriter>();
using (StreamReader sr = new StreamReader(workingDirectory + "data.csv"))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        var items = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

        StreamWriter w;
        if (!writers.TryGetValue(items[2], out w))
        {
            w = new StreamWriter(workingDirectory + items[2] + ".txt");
            writers.Add(items[2], w);
        }

        var times = items[1].Split(':');
        var digits = items.Skip(3)
                    .Select(x => { int i; return new { IsValid = int.TryParse(x, out i), Value = x }; })
                    .Where(x => x.IsValid).Select(x => x.Value);
        var data = new[] { Array.IndexOf(days, items[0]).ToString() }.Concat(times).Concat(digits);
        w.WriteLine(String.Join(",", data));
    }
}
foreach (var w in writers)
{
    w.Value.Close();
    w.Value.Dispose();
}

【讨论】:

  • 这对于一个文件来说非常有效......非常棒,非常感谢!如何添加一个简单的循环以相同的方式读取多个文件,并将输出数据添加到同一数据集(例如 M40、M08 等),或者更容易创建更多单独的文件?
  • 将此代码放入具有 2 个字符串参数的方法中 - 输入文件和输出文件前缀(或后缀)。使用后缀构成输出文件名:workingDirectory + items[2] + "_" + suffix + ".txt" 比循环调用这个方法。
  • 太棒了 - 我在 Matlab 中有相同类型的解决方案,但不确定它是否适用于 C# - 非常感谢。
【解决方案2】:

这是一个快速的尝试,但我认为它会帮助你实现目标。

var lines = new List<string> { 
    "Fr 23:59:59 M40 N04161K RX LAG 2 JNYT  17 STORE OCC 1 PRUD 1 RAW  -9 LAG   0",
    "Fr 23:59:59 M08  N09461M  %SAT   3  %CONG   0  MQ 0  EB 0  OSQ     0 NSQ     4",
    "Fr 23:59:59 M20 N09461M SAT   3%  SQ     0  FLOW     4  GN  13  STOC  9"
};
var options = RegexOptions.IgnorePatternWhitespace;
var regex = new Regex("(?: ^\\w\\w | -?\\b\\d+\\b )", options );

foreach (var l in lines ){
    var matches = regex.Matches( l );

    foreach(Match m in matches){
        Console.Write( "{0},", m.Value );
    }
    Console.WriteLine();
}

生产:

Fr,23,59,59,2,17,1,1,-9,0,
Fr,23,59,59,3,0,0,0,0,4,
Fr,23,59,59,3,0,4,13,9,

【讨论】:

    【解决方案3】:
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    
    namespace Program
    {
      public class TransformCsv
      {
        [STAThread]
        public static void Main(String[] args)
        {
          (new TransformCsv()).Run(@"c:\temp\MessExport_20110402_0000.csv", @"c:\temp\output.txt", LineFilterFunction);
        }
    
        public static Boolean LineFilterFunction(String line)
        {
          return line.Contains("M40") || line.Contains("M08");
        }
    
        ////////////////////
    
        private List<String> _dayOfWeek = new List<String>() { "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" };
    
        private Dictionary<String, String> _mReference =
          new Dictionary<String, String>()
          {
            // Add other M-reference mappings here.
            { "M40", "2" },
            { "M08", "3" },
            { "M20", "3" }
          };
    
        public void Run(String inputFilePath, String outputFilePath, Func<String, Boolean> lineFilterFunction)
        {
          using (var reader = new StreamReader(inputFilePath))
          {
            using (var writer = new StreamWriter(outputFilePath))
            {
              String line = null;
              while ((line = reader.ReadLine()) != null)
              {
                if (!String.IsNullOrWhiteSpace(line) && lineFilterFunction(line))
                  writer.WriteLine(this.GetTransformedLine(line));
              }
            }
          }
        }
    
        private static Char[] _spaceCharacter = " ".ToCharArray();
    
        private String GetTransformedLine(String line)
        {
          var elements = line.Split(_spaceCharacter, StringSplitOptions.RemoveEmptyEntries);
    
          var result = new List<String>();
          result.Add((_dayOfWeek.IndexOf(elements[0]) + 1).ToString());
          result.Add(elements[1].Replace(':', ','));
          result.Add(_mReference[elements[2]]);
          result.AddRange(elements.Skip(3).Where(e => this.IsInt32(e)));
    
          return String.Join(",", result);
        }
    
        private Boolean IsInt32(String s)
        {
          Int32 _;
          return Int32.TryParse(s, out _);
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多