正则表达式分析日志文件(多行)

时间:2016-01-14 13:57:15

标签: c# regex file parsing logging

我需要分析第三方工具创建的结果文件。因此,我尝试创建一个小型c#工具,它应该加载文件内容并执行正则表达式。内容如下:

[1] <Download> 13.01.2016 15:16:47
[ 

Name: foobar.tif

Status:              0 (ok)
]

[2] <Download> 13.01.2016 15:17:50
[
Name: foobar2.tif

Error: 7100: No file found!

]

[3] <Upload> 13.01.2016 15:17:53
[

Name: Company.tif

Size: 3476
Error: 7200: Unauthorized!

]

...

我尝试创建一个匹配此类内容的正则表达式模式。在此示例中,3个匹配包括我需要检查的4个组(索引1,2或3;任务下载/上载,文件名和状态或错误的值)。可以忽略所有其他信息,如时间戳或可选的“大小”属性。

这就是我的想法:

(?<Index>\[[0-9]+\]) (?<TaskName><[\w]+>)

但是现在这只匹配索引和任务名称,我不知道如何继续获取“名称”和“状态”或“错误”值,因为它们在另一行中。

编辑:

好的,我试图完成你的回答,这是我到目前为止所提出的:

\[(?<Index>[0-9]+?)\]\s<(?<Task>\w+?)>.+\n+\[[\s.]+Name\:\s(?<Name>.+)(?<Content>[\s\S]+?)\]

现在我得到索引,任务名称和名称。到目前为止方法还可以吗?接下来,我将尝试将错误/状态记录到组中。

3 个答案:

答案 0 :(得分:3)

默认情况下,正则表达式模式总是捕获多行。这种行为可以被覆盖,但如果这是你想要做的事情,那么你需要做的就是让它跨多行捕获。但是,有一些角色类会考虑换行字符。最值得注意的是,.字符类匹配除换行符之外的所有字符。因此,如果您想要捕获包含换行符在内的任何字符,则不能只使用.*,因为这只会匹配到当前行的结尾。

您可以使用(.|\n)*但是,如果可能,最好使用否定的字符类。例如,如果您需要在以下示例中获取括号内的值:

 [Value One] some
 random

 data
 [Value Two]

您可以使用(\[(?<value>[^]]*)\][^[]*)*。请注意,[^]]*用作括号内值的模式,[^[]*用作括号内所有内容的模式。否定的字符类只意味着它匹配列表中不是的任何字符。例如,[^abc]将匹配任何非abc的字符。所以,[^[]只意味着任何不是开放方括号的字符。由于换行符不是方括号,因此它将匹配换行符以及任何其他类型的字符。

我之所以说一个否定的字符类比(.|\n)*之类的东西更可取的原因是因为,为了使用(.|\n)*,你必须重复*懒惰(例如(.|\n)*?\[)。懒惰(即不贪婪)的重复导致大量的回溯,因此它们会损害性能。因此,尽可能使用否定字符类代替惰性重复是最好的。

答案 1 :(得分:1)

您可以在一个正则表达式中完成所有工作,但我认为编写和管理起来非常困难。我可以建议将它拆分为两个不同的正则表达式吗?您可以使用此选项获取索引,下载/上载字段以及不同组中的说明:

\[([1-9]+?)\]\s<\w+?>.+\n\[([\s\S]+?)\]

然后您可以获取包含该消息的组并将其应用于此正则表达式:

Name:\s(.+?)\n[\s\S]*?(Error:|Status:)\s+?(.+?)$

在使用上面的正则表达式之前,请务必在包含该消息的字符串上使用Trim(),否则正则表达式可能无法正常工作。

以下是一些使用正则表达式的C#代码:

Regex regex1 = new Regex("\\[([1-9]+?)\\]\\s<\\w+?>.+\\n\\[([\\s\\S]+?)\\]");
            MatchCollection matches = regex1.Matches(logMessage);

            foreach (Match match in matches)
            {
                String indexField = match.Groups[1].Value;
                String message = match.Groups[2].Value.Trim();
                if (String.IsNullOrEmpty(message) == false)
                {
                    Regex regex2 = new Regex("Name:\\s(.+?)\\n[\\s\\S]*?(Error:|Status:)\\s+?(.+?)$");
                    Match messageMatch = regex2.Match(message);
                    String name = messageMatch.Groups[1].Value.Trim();
                    String statusError = messageMatch.Groups[3].Value.Trim();
                }
            }

答案 2 :(得分:0)

你可以拿出某事。像自由间隔模式中的以下正则表达式:

~
\[(?<index>\d+)\]\s*
<(?<task>\w+)>(?s).*?
\[(?s).*?
Name:\s*(?<filename>[^\n]+)(?s).*?
(?:Status|Error):\s*(?<status>\d+)(?s).*?
\]
~