使用正则表达式解析日志文件

时间:2008-09-03 10:15:11

标签: c# regex

我正在为我们的内部日志文件(由log4php,log4net和log4j生成)处理解析器。到目前为止,我有一个很好的正则表达式来解析日志,除了一个恼人的位:一些日志消息跨越多行,我无法正确匹配。我现在的正则表达式是:

(?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}):\d{2}:\d{2}),\d{3})\s(?<message>.+)

日志格式(我用于测试解析器)是这样的:

07/23/08 14:17:31,321 log 
message
spanning
multiple
lines
07/23/08 14:17:31,321 log message on one line

当我立即运行解析器时,我只获得日志开始的行。如果我将其更改为跨越多行,我只得到一个结果(整个日志文件)。


@samjudson:

您需要将RegexOptions.Singleline标志传递给正则表达式,以便“。”匹配所有字符,而不仅仅是除了新行之外的所有字符(这是默认值)。

我试过了,但它匹配整个文件。我还尝试将消息组设置为。+? (非贪婪的),但它匹配一个单一的字符(这不是我正在寻找的)。

问题是消息的模式也在日期组上匹配,因此当它不在新行上中断时,它就会继续打开和打开。


我现在将此正则表达式用于消息组。它起作用,除非日志消息中的模式与日志消息的开头相同。

(?<message>(.(?!\d{2}/\d{2}/\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\s\[\d{4}\]))+)

5 个答案:

答案 0 :(得分:3)

这仅在日志消息不包含行开头的日期时才有效,但您可以尝试在“消息”组中为日期添加否定的预见断言:

(?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}:\d{2}:\d{2},\d{3})\s(?<message>(.(?!^\d{2}/\d{2}/
\d{2}))+)

请注意,这需要使用RegexOptions.MultiLine标志。

答案 1 :(得分:2)

你显然需要将“消息行”与“日志行”区分开来;如果你允许消息部分以新行之后的日期/时间开始,则根本无法确定消息的哪些部分以及什么不是。因此,不需要使用点,而是需要一个表达式,允许任何不包含换行符后跟日期和时间的内容。

但是,就个人而言,我不会使用正则表达式来解析整个日志条目。我更喜欢使用自己的循环迭代每一行,并使用一个简单的正则表达式来确定一行是否是新条目的开头。从可读性的角度来看,这也是我的偏好。

答案 2 :(得分:1)

您遇到的问题是您需要终止RegEx模式,以便它知道一条消息何时结束然后再开始。

当您在默认模式下运行时,换行符作为隐式终止符。

问题是如果你进入多线模式就没有终结器,所以模式会吞噬整个文件。非贪婪匹配尽可能只有一个字符。

现在,如果使用下一条消息的日期作为终结符,我认为你的解析器只能获取所有其他行。

文件中还有其他东西可以终止模式吗?

答案 3 :(得分:0)

您需要传递RegexOptions。单行标志中的正则表达式,以便“。”匹配所有字符,而不仅仅是除了新行之外的所有字符(这是默认值)。

答案 4 :(得分:0)

您可能会发现使用正确的解析器生成器解析文件要容易得多 - ANTLR可以在C#中生成一个...上下文自由解析器看起来很难,直到您“得到”它们 - 之后,它们更简单,比正则表达更友好...