【问题标题】:Parsing text file separated by comma解析用逗号分隔的文本文件
【发布时间】:2013-04-19 03:34:16
【问题描述】:

我正在开发一个应用程序来读取文本文件并绘制图表。文本文件将类似于

#Pattern Name Item1, Item2, Item3, gx1, gy1, gz1 
115, 80, 64, 30.752, 27.587, 15.806 
195, 151, 130, 108.983, 102.517, 66.353 
94, 123, 156, 43.217, 50.874, 93.700 
88, 108, 65, 26.158, 37.980, 17.288 
130, 129, 177, 68.096, 66.289, 127.182 
100, 190, 171, 71.604, 119.764, 122.349 
.........................................
........................................
#Pattern Name2 Item1, Item2, Item3, gx1, gy1, gz1 
115, 80, 64, 30.752, 27.587, 15.806 
195, 151, 130, 108.983, 102.517, 66.353 
94, 123, 156, 43.217, 50.874, 93.700 
88, 108, 65, 26.158, 37.980, 17.288 
130, 129, 177, 68.096, 66.289, 127.182 
100, 190, 171, 71.604, 119.764, 122.349

等等

我需要值 gx1,gy1 。我计划通过计算空格和逗号(每个 3 个)来阅读它们。但这听起来合适吗?是否有任何优化或更好的逻辑?

【问题讨论】:

  • 列名是否在文件中途重复?
  • 一个选项是内置的TextFieldParser类msdn.microsoft.com/en-us/library/…
  • @Ash 我不明白你说的是什么
  • 这在您的示例文件中出现了两次:#Pattern Name2 Item1, Item2, Item3, gx1, gy1, gz1
  • 他们经常出现。但我们需要单独处理。

标签: c# fileparsing


【解决方案1】:

使用 Linq 怎么样?

var allparts = File.ReadLines(filename)
                .Where(line => !line.StartsWith("#"))
                .Select(line => line.Split(','))
                .Select(parts => new {gx1=parts[3], gy1=parts[4]} ) 
                .ToList();

【讨论】:

  • 表现不佳。逐行阅读。当数据以 CSV 格式出现且不是学生样本时,CSV 文件可能会很大
  • @Regfor ReadLines 已经逐行执行了。不是File.ReadAllLines
  • @I4V 所以 var allparts 对每一行都是唯一的,我分别想要 2 个值。我会尽快检查并发表评论.. 谢谢
  • @Zigma allparts 将是一个匿名类型的列表,具有gx1 和gy1 属性(如allparts[i].gx1)
【解决方案2】:

您应该使用现有的 csv 解析器,例如 this。

但是,假设模式的名称是唯一的并且您想稍后访问它:

var gxDict = new Dictionary<string, List<Tuple<double, double>>>();
List<Tuple<double, double>> currentGxList = null;
foreach (string line in File.ReadLines(filePath))
{
    if (line.StartsWith("#Pattern"))
    {
        string[] headers = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        string patternField = headers.First();
        string patterName = string.Join(" ", patternField.Split().Skip(1).Take(2));
        List<Tuple<double, double>> gxList = null;
        if (gxDict.TryGetValue(patterName, out gxList))
            currentGxList = gxList;
        else
        {
            currentGxList = new List<Tuple<double, double>>();
            gxDict.Add(patterName, currentGxList);
        }
    }
    else
    {
        if (currentGxList != null)
        {
            string[] values = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            double gx1;
            double gy1;
            string gx1Str = values.ElementAtOrDefault(3);
            string gy1Str = values.ElementAtOrDefault(4);
            if (double.TryParse(gx1Str, out gx1) && double.TryParse(gx1Str, out gy1))
            {
                currentGxList.Add(Tuple.Create(gx1, gy1));
            }
        }
    }
}

// 现在可以这样访问了:

List<Tuple<double, double>> nameItem1Vals = gxDict["Name Item1"];
foreach (var xy in nameItem1Vals)
    Console.WriteLine("gx1: {0} gy1: {1}", xy.Item1, xy.Item2);

// 或循环:

foreach (var kv in gxDict)
{
    string pattern = kv.Key;
    Console.WriteLine("pattern: {0}", pattern);
    foreach (var xy in nameItem1Vals)
        Console.WriteLine("gx1: {0} gy1: {1}", xy.Item1, xy.Item2);
}

请注意,当涉及到IO 时,我会避免使用 Linq,因为您需要在文件级别进行事件处理,并且当我尝试解析也可能导致异常的输入时。

【讨论】:

  • 编辑:if (int.TryParse(gx1Str, out gx1) &amp;&amp; int.TryParse(gy1Str, out gy1))。正如您在问题中看到的那样,值的类型也是双倍的
  • @Zigma:谢谢。编辑了我的答案。
  • 我无法访问这些值。我需要他们将其作为 x , y 传递给 DataBindXY 方法。
  • @Zigma:因为我后来将字典的值从元组更改为列表。现在看看编辑后的版本。
  • 即使进行了一些小的修改,它也能正常工作。避免Linq因为不太清楚这一点。
【解决方案3】:

您拥有的是一个简单的 CSV 文件。我会推荐:

1) 使用 CSV 解析库(例如 http://www.filehelpers.com/)
2)自己逐行解析:

String[] lines = File.ReadAllLines(...);
foreach(String line in lines)
{
   String parts[] = line.Split(",", StringSplitOptions.IgnoreEmpty);
   double gx1 = Double.Parse(parts[5]);
   double gx2 = Double.Parse(parts[6]);
}

但是,您需要为您的特殊行添加一些验证/跳行

【讨论】:

  • @Regfor:与什么相比表现不佳?我知道它会对内存产生影响,但在某些时候,必须读取每一行,一次或一行...
  • CSV 文件可能很大。当巨大的 CSV 文件出现时 - 内存消耗巨大,与 line be line 读取相比,性能很慢。
【解决方案4】:

读取每一行然后 line.Split(", ") 怎么样? 你可以拥有:

var items = line.Split(", ");
var gx1 = items[3];
var gy1 = items[4];
var gz1 = items[5];

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多