2008-09-03 66 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#中生成一個...上下文自由解析器似乎很難,直到您「獲得」它們 - 之後,它們變得更簡單並比正則表達式更友好...