2008-09-03 186 views
2

我目前正在为我们的内部日志文件(由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}\]))+) 

回答

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标志。

0

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

1

您遇到的问题是您需要终止RegEx模式,以便知道何时一条消息结束,然后下一次启动。

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

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

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

在文件中是否还有其他可以终止该模式的内容?

2

您显然需要将“消息行”与“日志行”区分开来;如果你允许消息部分在一个新行之后以日期/时间开始,那么根本没有办法确定什么是消息的一部分,什么不是。所以,不要使用点,而需要一个表达式,它允许任何不包含换行符的日期和时间。

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

0

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