首页 > 解决方案 > 计算列表中字符串的出现次数并在控制台中显示

问题描述

我现在正在创建一个 Logparser,我可以逐行处理文件夹中的所有文件,并提取我想要的子字符串,即"fct=". 所有这些使用Regex,我把结果放在一个List. 现在我想Count在我的列表中出现每个字符串并显示它。

我正在使用 GroupBy 但是当我显示结果时,所有的出现都在1.

实际的:

 720 1x
 720 1x
 710 1x

它应该是:

 720 2x
 710 1x  

我能够发现问题是我逐行读取我的文件,所以如果该"fct="值不是在同一行上两次,它不会计算它,2但只计算它1出现的每一行。

所以我需要找到一种方法来逐行计算我的列表而不是我的文件。

我真的是初学者所以不知道如何做到这一点任何提示将不胜感激。

这是日志数据示例:

<dat>FCT=10019,XN=KEY,CN=ROHWEPJQSKAUMDUC</dat></logurl>
<dat>XN=KEY,CN=RTU FCT=4515</dat>LBZ=test.sqi</logurl>
<dat>XN=KEY,CN=RT</dat>FCT=10019</logurl>

我想显示:

 FCT=10019 2x
 FCT=4515 1x

我的代码:

   class Program
{

    static void Main(string[] args)
    {

        int counter = 0;
        string[] dirs = Directory.GetFiles(@"C:/LogParser/LogParserV1", "*.txt");
        StreamWriter sw = new StreamWriter("C:/LogParser/LogParserV1/test.txt");      
        char[] delimiters = { '<', ',', '&', ':', ' ', '\\', '\'' };
        string patternfct = "(?<=FCT=)[0-9]*";


        foreach (string fileName in dirs)
        {
            StreamReader sr = new StreamReader(fileName);

            {
                String lineRead;
                while ((lineRead = sr.ReadLine()) != null)
                {

                    //To find all the value of fct= occurence 
                    var listfct = Regex.Matches(lineRead, patternfct, 
  RegexOptions.IgnoreCase).Cast<Match>().Select(x => x.Value).ToList();


                   var fctGroups = listfct.GroupBy(i => i);
                    foreach (var grp in fctGroups)
                    {
                        var fct = grp.Key;
                        var total = grp.Count();
                        System.Console.WriteLine("fct=" + fct + " " + "Total=" + total);
                    }

                    counter++;
                }
                System.Console.WriteLine(fileName);

                sr.Close();
                sw.Close();
            }
        }

        // Suspend the screen.  
        System.Console.ReadLine();

    }
}
}

标签: c#linqfile

解决方案


您可以尝试在 Linq 的帮助下查询数据:

using System.Linq;
using System.Text.RegularExpressions;

...

Regex regex = new Regex("(?<=FCT=)[0-9]*", RegexOptions.IgnoreCase);

var records = Directory
  .EnumerateFiles(@"C:/LogParser/LogParserV1", "*.txt")
  .SelectMany(file => File.ReadLines(file))
  .SelectMany(line => regex
     .Matches(line)
     .Cast<Match>()
     .Select(match => match.Value))
  .GroupBy(number => number)
  .Select(group => $"FCT={group.Key} {group.Count()}x");

foreach (string record in records)
  Console.WriteLine(record);

演示:我们不能模仿目录和文件,所以我删除了

  Directory
    .EnumerateFiles(@"C:/LogParser/LogParserV1", "*.txt")
    .SelectMany(file => File.ReadLines(file))

但补充说testLines

  string[] testLines = new string[] {
    "<dat>FCT=10019,XN=KEY,CN=ROHWEPJQSKAUMDUC</dat></logurl>",
    "<dat>XN=KEY,CN=RTU FCT=4515</dat>LBZ=test.sqi</logurl>",
    "<dat>XN=KEY,CN=RT</dat>FCT=10019</logurl>",
  };

  Regex regex = new Regex("(?<=FCT=)[0-9]*", RegexOptions.IgnoreCase);

  var records = testLines
    .SelectMany(line => regex
       .Matches(line)
       .Cast<Match>()
       .Select(match => match.Value))
    .GroupBy(number => number)
    .Select(group => $"FCT={group.Key} {group.Count()}x");

  foreach (string record in records)
    Console.WriteLine(record);

结果:

FCT=10019 2x
FCT=4515 1x

编辑:如果要包含filerecords中,可以使用匿名对象:

var records = Directory
  .EnumerateFiles(@"C:/LogParser/LogParserV1", "*.txt")
  .SelectMany(file => File
     .ReadLines(file)
     .Select(line => new {
        file = file,
        line = line,  
      }))
  .SelectMany(item => regex
     .Matches(item.line)
     .Cast<Match>()
     .Select(match => new {
        file   = item.file,
        number = match.Value  
      }))
  .GroupBy(item => new {
     file   = item.file, 
     number = item.number
   })
  .OrderBy(group => group.Key.file)
  .ThenBy(group => group.Key.number)
  .Select(group => $"{group.Key.file} has FCT={group.Key.number} {group.Count()}x")

推荐阅读