从一个StreamReader过滤后的数据进行小计(Performing a subtotal on

2019-08-03 07:30发布

编辑作为的问题是没有答案

我有根据1个标准滤波的输出(前3个数字是110210或310,得到3个不同的基团),以从StreamReader的控制台。 问编辑,因为第一个答案是字面解决我给了具体的例子,我使用的是真正的字符串是450个ASCII字符。 我已经调整的例子字符串解决这个问题,任何对样本数据适用于我有什么会工作。

所以我真正需要的东西,可以,取决于前3个数字,从采取预先指定的已知位置的3个字母(210的它会是性格插槽14-16,然后使用,作为一个子类别,总结所有条目在字符时隙33-37和输出那些)。

例如字符串:

210!!!!123244AAA75AWEHUIHJUAS!!!11111
210???1223455ABC76554HJHSDFQ????22222
210--32455623ABCFFCDGHDSFAS-----33333
310         1232451    2ABC34       GAERsASDFASDG1234523   44444
310 1234a354GDSAASDR  3 AAA  GF234523653hfdssdgSDASDF      11111
310 12378HJK1234        ABC HJHJK123462 ASDHDFS FA REW     22222
4101111ASDJF     1ABCASF        D1234    ASGF66666
4102222QW12362ER2 ABC 23459876HJKXC          11111
41033333T123 1RWE AAA  ASDFHJKRTR  WQ        22222

在本月底,我的输出将是:

210 AAA 11111
210 ABC 55555
310 ABC 66666
310 AAA 11111
410 ABC 77777
410 AAA 22222

在ABC,AAA等总是在同一起跑线数相同的位置,但将每个起始编号不同。

同样被总结了量的位置也仅在每各起始编号相同的位置。

我试着加入一些string.split到现有的代码(如下图),但还没有任何运气。

// 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)
    {
        var beginning = line.Substring(0, 3);
        if (beginning != "210" && beginning != "310" && beginning != "410")
            continue;
        list.Add(line); // Add to list.
        Console.WriteLine(line); // Write to console.
    }
}

Answer 1:

(这里发布这个答案,因为其他问题被关闭。)使用ReadAllText将是低效的大文件。

public static class LinqToTextReader {
    public static IEnumerable<string> AsEnumerable(this TextReader reader) {
        string line;
        while ((line = reader.ReadLine()) != null) {
            yield return line;
        }
    }
}

class Program {
    static void Main(string[] args) {
        using (StreamReader reader = new StreamReader("file.dat")) {
            var locations = new Dictionary<string, int[]>() {
                {"210", new [] {406, 409, 129, 140, 142, 153}},
                {"310", new [] {322, 325, 113, 124, 126, 137}},
                {"410", new [] {478, 481, 113, 124, 126, 137}}
            };

            var query =
                from line in reader.AsEnumerable()
                let lineStart = line.Substring(0, 3)
                where lineStart == "210" || lineStart == "310" || lineStart == "410"
                let currentLocations = locations[lineStart]
                select new {
                    letters = line.Substring(currentLocations[0], currentLocations[1]),
                    value =
                        int.Parse(line.Substring(currentLocations[2], currentLocations[3])) +
                        int.Parse(line.Substring(currentLocations[4], currentLocations[5]))
                };

            //It should be possible to combine the two queries
            var query2 = 
                from item in query
                group item by item.letters into letterGroup
                select new {
                    letters = letterGroup.Key,
                    total = letterGroup.Sum(item => item.value)
                };

            foreach (var item in query2) {
                Console.WriteLine(item.letters);
                Console.WriteLine(item.total);
            }
        }
    }
}


Answer 2:

string input = File.ReadAllText("file.dat");
var result = Regex.Matches(input, "(210|310|410).*?([A-C]{3})([0-9]{5})")
    .Cast<Match>()
    .Select(m => new { 
        P1 = m.Groups[1].Value, 
        P2 = m.Groups[2].Value, 
        P3 = Convert.ToInt32(m.Groups[3].Value)
    })
    .GroupBy(x => new{x.P1,x.P2})
    .Select(x=>String.Format("{0} {1} {2}",x.Key.P1,x.Key.P2,x.Sum(y=>y.P3)))
    .ToList();


文章来源: Performing a subtotal on filtered data from a streamreader