Разобрать записи многострочного журнала с помощью регулярных выражений
Я пытаюсь проанализировать записи журнала в приложении C# с помощью этого регулярного выражения: (^[0-9]{4}(-[0-9]{2}){2}([^|]+\|){3})(?!\1)
для журналов в формате вроде [дата (в каком-то формате)] | [уровень] | [имя приложения] | [сообщение].
Где (я думаю):
^
соответствует началу строки (включено /gm для regex101)[0-9]{4}(-[0-9]{2}){2}
с последующим началом даты, как 2015-03-03([^|]+\|){3})
с последующим указанием даты, уровня журнала и имени приложения(?!\1)
с последующим не началом новой записи в журнале (должно быть сообщение)
Например, у меня есть следующие 4 записи журнала (разделенные новой строкой для пояснения):
2015-03-03 19: 30: 47.2725 | INFO |MyApp| Это однострочный журнал. 2015-03-03 19: 31: 29.1209 | INFO |MyApp| В этом сообщении есть несколько линии с 2015-03-03 дата в этом. 2015-03-03 19: 32: 50.1106 | INFO |MyApp| Это сообщение журнала имеет несколько строк но только текст. 2015-03-03 19:33:20.2683| ОШИБКА |MyApp| Это сообщение журнала имеет несколько строк, но также какой-то запутанный текст, как 2015-03-03 19:33:20.2683| ОШИБКА | который должен все еще быть действительным сообщением журнала.
Но регулярное выражение не захватывает сообщение, когда я тестирую его на регулярном выражении, вероятно, потому, что я не понимаю, как захватить негативную перспективу.
Если я включу .*
в регулярном выражении: (^[0-9]{4}(-[0-9]{2}){2}([^|]+\|){3}).*(?!\1)
это соответствует сообщению, но только одной строке (потому что .
не соответствует переводу строки).
Итак, как я могу перехватить (многострочное) сообщение?
3 ответа
Вы можете использовать это регулярное выражение:
(^\d{4}(-\d{2}){2}([^|]+\|){3})([\s\S]*?)\n*(?=^\d{4}.*?(?:[^|\n]+\|){3}|\z)
Это регулярное выражение должно работать и в C#, просто убедитесь, что вы используете MULTILINE
флаг.
Нечто подобное должно работать.
Смотрите комментарии в регулярном выражении.
(мод: сделать разрыв строки необязательным для EOS или однострочного сообщения)
@"(?m)^[0-9]{4}(?:-[0-9]{2}){2}(?:[^|\r\n]+\|){3}((?:(?!^[0-9]{4}(?:-[0-9]{2}){2}(?:[^|\r\n]+\|){3}).*(?:\r?\n)?)+)"
Отформатированный ( с этим):
(?m) # Modifier - multiline
^ # BOL
[0-9]{4} # Message header
(?: - [0-9]{2} ){2}
(?: [^|\r\n]+ \| ){3}
( # (1 start), The Message
(?:
(?! # Assert, not a Message header
^ # BOL
[0-9]{4}
(?: - [0-9]{2} ){2}
(?: [^|\r\n]+ \| ){3}
)
.* # Line is ok, its part of the message
(?: \r? \n )? # Optional line break
)+
) # (1 end)
Выход:
** Grp 0 - ( pos 0 , len 74 )
2015-03-03 19:30:47.2725|INFO|MyApp|This is a single line log message.
** Grp 1 - ( pos 36 , len 38 )
This is a single line log message.
--------------
** Grp 0 - ( pos 74 , len 108 )
2015-03-03 19:31:29.1209|INFO|MyApp|This log message has multiple
lines with
2015-03-03
a date in it.
** Grp 1 - ( pos 110 , len 72 )
This log message has multiple
lines with
2015-03-03
a date in it.
--------------
** Grp 0 - ( pos 182 , len 97 )
2015-03-03 19:32:50.1106|INFO|MyApp|This log message has
multiple lines
but just text only.
** Grp 1 - ( pos 218 , len 61 )
This log message has
multiple lines
but just text only.
--------------
** Grp 0 - ( pos 279 , len 186 )
2015-03-03 19:33:20.2683|ERROR|MyApp|This log message has multiple lines but
also some confusing text like
2015-03-03 19:33:20.2683|ERROR| which should
still be a valid log message.
** Grp 1 - ( pos 316 , len 149 )
This log message has multiple lines but
also some confusing text like
2015-03-03 19:33:20.2683|ERROR| which should
still be a valid log message.
Какой движок регулярных выражений вы используете? В Java, например, есть флаг, чтобы сказать "." соответствовать символам новой строки.
Следующее регулярное выражение, кажется, делает трюк:
/(([0-9]{4})(-[0-9]{2}){2}([^|]+\|){3})((.(?!\2))*)/sg
Изменения, которые я внес в ваш запрос, были в основном некоторой очисткой (ваша группа по сбору данных была неверной) Затем я добавил. и * в этой последней группе захвата. https://regex101.com/r/fU1vV1/2
Наиболее важной частью является использование флагов sg. г заставляет его получать все совпадения. s заставляет все это рассматривать как одну строку (иначе ваш негативный взгляд никогда не сработает). Все это было бы излишним, если бы вы могли гарантировать, что комментарии были в одной строке (что они и есть в вашем примере), поскольку вы могли просто захватить их до конца строки.