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

时间:2015-11-20 14:54:26

标签: c# regex

我有大量的日志文件,在这里我需要阅读并找到所有错误和错误,如下所示。

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.
-------------------- |  ----------------------------------------------

3 个答案:

答案 0 :(得分:2)

您是否在寻找类似的东西( 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()方法(但是,更多Linq https://www.nuget.org/packages/morelinq/有他们),所以代码将是精简的:

  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);

答案 1 :(得分:1)

这是使用字典的解决方案(假设处理编号是唯一的)。基本上当它遇到“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);
        }
    }
}

答案 2 :(得分:1)

对于像这样的事情,正则表达式绝对是一个很好的选择。只要您知道自己在做什么,因为它是一种声明性语言,它可能比任何必要的替代方案更清晰,更简单,更灵活。

正则表达式模式的许多变体都可以使用,它取决于您的具体需求,但是以下模式中的某些内容应该对您有用:

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
    }