C#使用正则表达式读取日志文件中的错误

本文关键字:文件 错误 日志 读取 正则表达式 | 更新日期: 2023-09-27 18:23:49

我有一个巨大的日志文件,在这个文件中,我需要阅读并找到所有的错误,错误的格式如下。

TX: 000001270
PROCESSING: 2015-666-001211-0000
CONVERSION FAILURE!
ERROR: the given number not find in  transaction table.
Removed TransactionSet
TX: 0000018887
PROCESSING: 2915-966-001888-0000
CONVERSION FAILURE!
ERROR: Object reference not set an instance of object.
Removed TransactionSet

有人能帮我用正则表达式将所有错误读取到带有处理编号和错误消息的数据表/列表中吗。(或者)请建议有没有其他更好的解决方案来阅读这篇文章。

预期输出格式(如列表或数据表)

Processing           |  ErrorMessage
-------------------- |  ----------------------------------------------
2015-666-001211-0000 |  the given number not find in  transaction table.
-------------------- |  ----------------------------------------------
2915-966-001888-0000    Object reference not set an instance of object.
-------------------- |  ----------------------------------------------

C#使用正则表达式读取日志文件中的错误

你在寻找这样的东西吗(Linq):

  String prefix = "ERROR: ";
  var result = File
   .ReadLines(@"C:'MyLog.txt")
   .Where(line => line.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
   .Select(line => line.Substring(prefix.Length)); // <- let's remove "ERROR: " prefix
  // the given number not find in  transaction table. 
  // Object reference not set an instance of object.
  String report = String.Join(Environment.NewLine, result);

编辑:不幸的是,标准Linq既不实现Lag()方法,也不实现Lead()方法(但是,More Linqhttps://www.nuget.org/packages/morelinq/有),所以代码将是combersome:

  String processing = "";
  var result = File
   .ReadLines(@"C:'MyLog.txt")
   .Where(line =>
     line.StartsWith("ERROR: ", StringComparison.OrdinalIgnoreCase) ||
     line.StartsWith("PROCESSING: ", StringComparison.OrdinalIgnoreCase))
   .Select(line => { // Lag() emulation
      if (line.StartsWith("PROCESSING: ", StringComparison.OrdinalIgnoreCase)) {
        processing = line.Substring("PROCESSING: ".Length);
        return "";
      }
      else
        return processing + " | " + line.Substring("ERROR: ".Length);
      })
   .Where(line => !String.IsNullOrEmpty(line));
   //2015-666-001211-0000 | the given number not find in  transaction table.
   //2915-966-001888-0000 | Object reference not set an instance of object.
   String report = String.Join(Environment.NewLine, result);

Regex绝对是一个很好的、合适的选择。只要你知道你在用它做什么,因为它是一种声明性语言,它可能比任何命令式替代语言都更干净、更简单、更灵活。

regex模式有很多变体可以工作,这取决于您的特定需求,但以下模式的某些内容应该适合您:

PROCESSING: (?<processing>[^'r'n]*)(.|'r|'n)*?ERROR: (?<error>[^'r'n]*)

你可以这样使用它:

string pattern = @"PROCESSING: (?<processing>[^'r'n]*)(.|'r|'n)*?ERROR: (?<error>[^'r'n]*)";
foreach (Match m in Regex.Matches(input, pattern))
    {
        string processing = m.Groups["processing"].Value;
        string error = m.Groups["error"].Value;
        // Insert into database
    }

这里有一个使用字典的解决方案(假设处理编号是唯一的)。基本上,当它遇到"PROCESSING:"行时,它会在字典中添加一个条目,其中包含一个空字符串作为值,然后下次遇到"ERROR:"行,它会设置上一个插入键的值。测试了100万条错误记录(因此700万行,150MB文件大小),耗时4.7秒

Dictionary<string, string> Errors = new Dictionary<string, string>();
string lastProcessingNumber = string.Empty;
using (StreamReader reader = new StreamReader("log.txt"))
{
    while(!reader.EndOfStream)
    {
        string line = reader.ReadLine();
        if(line.StartsWith("PROCESSING"))
        {
            lastProcessingNumber = line.Replace("PROCESSING: ", string.Empty);
            Errors.Add(lastProcessingNumber, string.Empty);
        }
        if(line.StartsWith("ERROR") && lastProcessingNumber != string.Empty)
        {
            Errors[lastProcessingNumber] = line.Replace("ERROR: ", string.Empty);
        }
    }
}