Разбор файла журнала с регулярными выражениями - PullRequest
2 голосов
/ 03 сентября 2008

В настоящее время я работаю над парсером для наших внутренних файлов журналов (генерируемых 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 ]

3 голосов
/ 03 сентября 2008

Это будет работать только в том случае, если сообщение журнала не содержит даты в начале строки, но вы можете попробовать добавить отрицательное предварительное утверждение для даты в группе «сообщения»:

(?<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.

2 голосов
/ 03 сентября 2008

Вам, очевидно, нужно, чтобы «строки сообщений» можно было отличить от «строк журнала»; если вы позволите части сообщения начинаться с даты / времени после новой строки, то просто невозможно будет определить, что является частью сообщения, а что нет. Поэтому вместо использования точки вам нужно выражение, которое разрешает все, что не включает символ новой строки, за которым следуют дата и время.

Однако лично я бы не использовал регулярное выражение для разбора всей записи журнала. Я предпочитаю использовать свой собственный цикл для итерации по каждой строке и использовать одно простое регулярное выражение, чтобы определить, является ли строка началом новой записи или нет. Также с точки зрения читабельности это будет иметь мое предпочтение.

1 голос
/ 03 сентября 2008

Проблема, с которой вы столкнулись, заключается в том, что вам нужно завершить шаблон RegEx, чтобы он знал, когда заканчивается одно сообщение, а затем начинается следующее.

Когда вы работали в режиме по умолчанию, символ новой строки работал как неявный терминатор.

Проблема в том, что если вы перейдете в многострочный режим, терминатора не будет, поэтому шаблон сожрет весь файл. Нежадное совпадение соответствует нескольким символам, которые могут быть только одним.

Теперь, если использовать в качестве терминатора дату следующего сообщения, я думаю, что ваш парсер получит только все остальные строки.

Есть ли в файле что-то еще, что могло бы прервать шаблон?

0 голосов
/ 03 сентября 2008

Возможно, вам будет намного проще проанализировать файл с помощью правильного генератора синтаксических анализаторов - ANTLR может генерировать его в C # ... Свободные от контекста синтаксические анализаторы только кажутся сложными, пока вы их не «получите» - после этого они становятся намного проще и удобнее в использовании, чем регулярные выражения ...

0 голосов
/ 03 сентября 2008

Вам необходимо сдать RegexOptions. Одиночный флаг в регулярном выражении, так что "." соответствует всем символам, а не только всем символам, кроме новых строк (по умолчанию).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...