【问题标题】:Analysing line by line and storing if meets criteria, else ignore逐行分析,如果符合条件则存储,否则忽略
【发布时间】:2012-11-29 10:27:05
【问题描述】:

我在这个上挖了很多,但没有找到我正在寻找的东西。

INPUT:多行(数百行,偶尔数千行)ASCII 文本,长度从 97 个字符到 500 多个字符不等。我是否要保留此数据的标准纯粹包含在前 3 个字符(总是数字 - 任意值 100,200 和 300 是我感兴趣的值)。

需要的输出只有以100、200或300开头的那些,其余的我可以忽略。

这是我的流式阅读器,目前输出到控制台:

using System;
using System.Collections.Generic;
using System.IO;

class Program
{
public void Do
{

    // Read in a file line-by-line, and store in a List.

    List<string> list = new List<string>();
    using (StreamReader reader = new StreamReader("File.dat"))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            list.Add(line); // Add to list.
            Console.WriteLine(line); // Write to console.
        //    Console.ReadLine();
        }
    }
}
}

我希望写一行

IF {
FIRST3CHAR != (100,200,300) }
then skip,

但我不确定如何定义 FIRST3CHAR 类。这是将对原始数据执行的唯一过滤器。

之后,我将根据其中包含的其他标准分析此过滤后的数据集,但在寻求任何帮助之前,我会自己试一试。

【问题讨论】:

    标签: c# filter streamreader


    【解决方案1】:

    这段代码更具可读性,可以做你想做的事:

    var allowedNumbers = new[]{ "100", "200", "300" };
    IEnumerable<String> lines = File
                       .ReadLines("File.dat")
                       .Where(l => allowedNumbers.Any(num => l.StartsWith(num)));
    

    现在您可以使用foreach 枚举这些行:

    foreach(string line in lines)
    {
        Console.WriteLine(line); // Write to console.
    }
    

    既然您想将这些行添加到List&lt;string&gt;,您可以使用Enumerable.ToList 而不是foreach

    List<string> list = lines.ToList();
    

    【讨论】:

    • 甜蜜的解决方案,但潜在的瓶颈。
    • @PLB:您认为瓶颈在哪里?请注意,ReadLines 在返回结果之前不会将整个文件读入内存。有关详细信息,请参阅其文档的备注部分。
    • @DanielHilgarth Where 将遍历读取行,any 将遍历 allowedMembers。虽然这可以在循环中完成。我并不是说这是一个糟糕的解决方案。不要误会我的意思。 :)
    • @PLB:你会如何在一个循环中做到这一点?
    • @PLB:我认为您没有理解延迟执行的意义。将Where 理解为循环中的if 子句,而不是附加循环。上面使用的Any 与 Marc Gravells || 方法相同。
    【解决方案2】:

    在最简单的层面上:

    if(line.StartsWith("100") || line.StartsWith("200") || line.StartsWith("300"))
    {
        list.Add(line); // Add to list.
        Console.WriteLine(line); // Write to console.
    }
    

    如果文件很大(如数十万行),那么将其实现为迭代器块可能也值得考虑。但是“开始”测试非常简单。

    如果您需要更大的灵活性,我会考虑使用正则表达式;例如:

    static readonly Regex re = new Regex("^[012]00", RegexOptions.Compiled);
    
    ...
    while (...)
    {
        if(re.IsMatch(line))
        {
            list.Add(line); // Add to list.
            Console.WriteLine(line); // Write to console.
        }
    }
    

    【讨论】:

    • 如果不需要实时输出,您也可以考虑为输出填充 StringBuilder
    • @trippino 我们不知道 OP 将列表用于什么目的;我不认为 stringbuilder 在这里适用。控制台对我来说就像一个 UI 跟踪器 - 保持“原样”可能很好
    • 是的,这只是一个加快调试速度的提示
    • 下一步是对于每 100 个起始行,查找位置 40-45 中的数字,并通过字符位置 20-23 中的变量对它们进行小计,对于每行 200(和按 24-26 中的变量进行小计,转到 50-55,对于 300、27-29,转到 60-65 等。最终输出将是这些总计在 20-23 等中的各个类别中分组)每 100 , 200 和 300 位起始数字。
    【解决方案3】:

    您是否有理由不将此条件添加到循环中?

    while ((line = reader.ReadLine()) != null)
    {
        var beginning = line.Substring(0, 3);
        if(beginning != "100" && beginning != "200" && beginning != "300")
            continue;
        list.Add(line); // Add to list.
        Console.WriteLine(line); // Write to console.
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-06
      • 1970-01-01
      • 2014-03-08
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      相关资源
      最近更新 更多