【问题标题】:Uploading Parsing a text file with ASP.NET MVC 3使用 ASP.NET MVC 3 上传解析文本文件
【发布时间】:2012-05-10 15:42:49
【问题描述】:

所以我正在尝试上传然后解析具有以下格式的文本文件:

3 月 29 日 19:23:51,667|DEBUG|1    |1:正在初始化 lorem ipsum...
3 月 29 日 19:23:31,682|ERROR|1    |1:启动 Foo.Bar.Launcher 时出现 Lorem.Ipsum.Exception
System.Blah.LoremException: Lorem ipsum dolor sit amet, consectetur adipisicing elit...
在 System.Lorem.Ipsum.Dolor.foo()
在 System.Lorem.Ipsum.Dolor.foo()
...
3 月 30 日 22:23:23,667|DEBUG|1    |1:正在初始化 lorem ipsum...
Apr 02 17:24:17,413|ERROR|4    |4:Lorem 无法 ipsum... System.DolorException:对象引用未设置为对象的实例。
在 Lorem.Ipsum.Dolor.IpsumDbController..ctor()

还有错误类:

public class Error
{
    public int ID { get; set; }
    public string Date { get; set; }
    public string Description { get; set; }
    public string ErrorType { get; set; }
}

哪里有两个错误:

错误 1

Mar 29 19:23:33 - 是 Date
System.Blah.LoremException - 是 ErrorType。
Lorem ipsum dolor sit amet, consectetur adipisicing elit - 是描述

错误 2

Apr 02 17:24:17 - 是 Date
System.DolorException - 是 ErrorType。
对象引用未设置为对象的实例。 - 是描述

有没有一种简单的方法可以解析字符串(通过正则表达式?或不?)?如果字符串包含 ERROR,我正在考虑拆分字符串,然后将下一行分配给 ErrorType。

我不太确定我会怎么做,所以任何帮助都将不胜感激!

更新:模式确实不一致,所以我对 String.Split 解决方案不是很有信心。

一般规则是:

全部 |错误|将有一个日期(我们的字符串日期),System.blah.LoremException (我们的错误类型),然后是一个异常消息(我们的描述)

ErrorType & Description 可能与 ERROR 字符串内联或在下一行。

【问题讨论】:

  • 到目前为止你有什么进展吗?我做了类似的事情,我使用 string.split 将信息与我的文件分开。
  • 还没有,不在我的开发 PC 中。我明天试试!
  • 好的,请看我的回答

标签: c# regex asp.net-mvc-3 parsing


【解决方案1】:

我会结合使用 StreamReader 和正则表达式来处理解析。

    private static List<Error> ParseErrors(string filepath)
    {
        Regex parser = new Regex(@"^(?<date>\w{3}\s\d{1,2}\s\d{1,2}(?::\d{1,2}){2}),[^\|]+\|ERROR\|[^:]+\s*(?<description>.+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        string line = string.Empty;
        Match curMatch = null;
        var errorLog = new List<Error>();

        using (StreamReader sReader = new StreamReader(filepath))
        {
            while (!sReader.EndOfStream && (line = sReader.ReadLine()) != null)
            {
                curMatch = parser.Match(line);
                if (curMatch.Success)
                {
                    errorLog.Add(new Error()
                    {
                        ID = errorLog.Count, /* not sure how you assign ids? */
                        Date = curMatch.Groups["date"].Value.Trim(),
                        Description = curMatch.Groups["description"].Value.Trim(),
                        ErrorType = sReader.ReadLine().Trim()
                    });
                }
            }
        }
        return errorLog;
    }

这背后的逻辑基本上是在流中逐行迭代以寻找与正则表达式的匹配。正则表达式本身只适合“ERROR”行,因此不会匹配“DEBUG”等。

如果该行与表达式匹配,则将一个新的“错误”类实例放入列表中,并使用正则表达式中的解析值来填充字段。要填写“ErrorType”字段,我只需阅读匹配后的下一行。

编辑

好的,我能看到的最好方法是当异常在同一行时匹配错误消息末尾的尾随“...”,然后尝试进一步匹配。

修改后的代码:

    private static List<Error> ParseErrors(string filepath)
    {
        Regex parser = new Regex(@"^(?<date>\w{3}\s\d{2}\s\d{1,2}(?::\d{1,2}){2}),[^\|]+\|ERROR\|[^:]+:\s*(?<description>.+?)(?:\.\.\.\s*(?<type>.+))?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        string line = string.Empty;
        Match curMatch = null;
        var errorLog = new List<Error>();

        using (StreamReader sReader = new StreamReader(filepath))
        {
            while (!sReader.EndOfStream && (line = sReader.ReadLine()) != null)
            {
                curMatch = parser.Match(line);
                if (curMatch.Success)
                {
                    errorLog.Add(new Error()
                    {
                        ID = errorLog.Count, /* not sure how you assign ids? */
                        Date = curMatch.Groups["date"].Value.Trim(),
                        Description = curMatch.Groups["description"].Value.Trim(),
                        ErrorType = (curMatch.Groups["type"].Success ? curMatch.Groups["type"].Value : sReader.ReadLine().Trim())
                    });
                }
            }
        }
        return errorLog;
    }

【讨论】:

  • 看起来很结实!明天试试!
  • 如果没有大样本来查看正则表达式可能有点不完整。如果在某些情况下它不起作用,请告诉我,我会对其进行调整。
  • 使得制作合理的模式变得更加困难,因为现在很多解析都是best-guess。您可以寻找 System\.在字符串中查找异常开始的位置,但这意味着您将无法捕获自定义异常。有什么方法可以修改记录错误的方式并提出更标准化的登录模式?
  • 遗憾的是,我不控制日志 :( 我只是接受并解析它们。
  • 好吧,编辑了我的答案。这仍然是一个“最佳猜测”。
【解决方案2】:

我会按照你的想法去做。拆分| 上的每一行,检查第二个元素是否等于ERROR,如果是,假设我需要处理该行和下一行。

【讨论】:

  • 谢谢!不过会等待其他答案!我真的很期待有神一样的正则表达式技能的人会来。另外,我现在无法编写代码。
  • 您当然可以使用 RegEx 来做到这一点,但我不确定您会获得什么。 RegEx 往往是一个大而缓慢的锤子。除非必须,否则我不会去那里。
【解决方案3】:

如果你在循环中使用类似的东西......你也可以像我之前提到的那样使用 split,这样可能会更有效一些

if (line.Contains("ERROR"))
                {
                    data = true;
                    continue;
                }


                if (data)
                    //here you deal with the following line

【讨论】:

    【解决方案4】:

    我解决了它,虽然它不是最优雅的解决方案,所以如果您有其他答案,请随时在此处发布。

        public static List<Error> ParseErrors(string filepath)
        {
            //separated the two regex
            Regex dateRegex = new Regex(@"^\w{3}\s\d{2}\s\d{2}:\d{2}:\d{2}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            Regex errorRegex = new Regex(@"((?<type>System.*?Exception):\s(?<description>.*\.))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    
            string CurrentLine = string.Empty;
            string NextLine = string.Empty;
    
            List<Error> errorLog = new List<Error>();
    
            using (StreamReader sReader = new StreamReader(filepath))
            {
                while (!sReader.EndOfStream && (CurrentLine = sReader.ReadLine()) != null)
                {
    
                    if (CurrentLine.Contains("|ERROR|"))
                    {
    
                        Match DateMatch = dateRegex.Match(CurrentLine);
                        Match ErrorMatch = errorRegex.Match(CurrentLine);
    
                        string date = DateMatch.Groups[0].Value.Trim();
                        string errorType = string.Empty;
                        string description = string.Empty;
    
                        //Check if error type and description is residing in the current line, otherwise, check at the next line
                        if (!ErrorMatch.Groups["type"].Value.Equals("") && !ErrorMatch.Groups["description"].Value.Equals(""))
                        {
                            errorType = ErrorMatch.Groups["type"].Value.Trim();
                            description = ErrorMatch.Groups["description"].Value.Trim();
                        }
                        else
                        {
                            NextLine = sReader.ReadLine();
                            ErrorMatch = errorRegex.Match(NextLine);
                            errorType = ErrorMatch.Groups["type"].Value.Trim();
                            description = ErrorMatch.Groups["description"].Value.Trim();
                        }
    
                        Error NewError = new Error();
                        NewError.Date = date;
                        NewError.ErrorType = errorType;
                        NewError.Description = description;
    
                        //a bit lazy with the regex, just take the first sentence of the description if it has multiple sentences.
                        if (NewError.Description.Contains(". "))
                            NewError.Description = NewError.Description.Substring(0, NewError.Description.IndexOf(". "));
    
                        // Do not add if it's a custom exception.
                        if(!NewError.Description.Equals("") && !NewError.Description.Equals(""))
                            errorLog.Add(NewError);
                    }
                }
            }
    
            return errorLog;
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-20
      • 2011-11-20
      • 2011-08-16
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      相关资源
      最近更新 更多