Как мне сопоставить последнее вхождение сложного повторяющегося шаблона - PullRequest
1 голос
/ 29 января 2020

ПРИМЕЧАНИЕ
Принятый ответ @Toto, в конечном счете, лучше работает в реальном мире для большого файла с множеством возможных совпадений, однако, если вы используете аналогичное регулярное выражение для файла любого размер, только с несколькими возможными совпадениями, тогда ответ @Pavel Lint будет в порядке и, возможно, будет быстрее, хотя я не проверял скорость. Имейте в виду, что здесь различия в миллисекундах, поэтому на самом деле не так много, если вы не делаете это большое количество раз подряд.


У меня есть следующая строка, которая является частью a SQL Файл журнала ошибок (изменен для ясности):

2020-01-27 11: 12: 00.72 Резервное копирование журнала. База данных: ReportServerTempDB, дата (время создания): 2019/05/22 (12:31:06), первый LSN: 79: 1911: 1, последний LSN: 79: 1933: 1, количество устройств дампа: 1, информация об устройстве : (FILE = 1, TYPE = DISK: {'E: \ SQLLogDumps \ ReportServerTempDB_tlog_20200127111200.trn'}). Это только информационное сообщение. Никаких действий пользователя не требуется.
2020-01-27 11: 21: 47,95 Ошибка входа: 17806, уровень серьезности: 20, состояние: 14.
2020-01-27 11: 21: 47,95 Возникновение входа в систему номер один

2020-01-27 11: 21: 47,95 Ошибка входа: 18452, уровень серьезности: 14, состояние: 1.
2020-01-27 11: 21: 47,95 Вход в систему не выполнен. Логин входит в ненадежный домен и не может использоваться со встроенной аутентификацией. [КЛИЕНТ: 192.168.4.208]
2020-01-27 11: 21: 47,95 Ошибка входа: 17806, уровень серьезности: 20, состояние: 14.
2020-01-27 11: 21: 47,95 Вход в систему Вхождение номер два

2020-01-27 11: 21: 47,95 Ошибка входа: 18452, Серьезность: 14, Состояние: 1.
2020-01-27 11: 21: 47,95 Вход в систему не выполнен. Логин входит в ненадежный домен и не может использоваться со встроенной аутентификацией. [КЛИЕНТ: 192.168.4.208]

Текст, выделенный жирным шрифтом выше, совпадает с выражением, которое я написал до сих пор.
Я хочу найти последнее вхождение строка, содержащая «Серьезность: 20» плюс следующая строка, также называемая вторым жирным шрифтом. Тем не менее, в дикой природе может быть любое количество экземпляров в одном документе.

Я поиграл на regex101.com и прочитал большую часть контента на регулярные-выражения.info , но не могу сделать регулярное выражение, которое работает.

Текущее выражение, которое у меня есть:
^.*Severity: 20.*\R^.*(?!(^.*\R)*Severity: 20)

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

Возможно ли сопоставить только последнее вхождение шаблона? Если да, то как?

Чтобы уточнить, я ищу чистое регулярное выражение. Я знаю, что это возможно в Python, возвращая все совпадения в виде списка, затем получая последний элемент списка, но у меня нет такой опции. Кроме того, я использую поиск регулярных выражений в Notepad ++, который, как мне кажется, использует версию регулярных выражений Boost .


UPDATE

Оба из приведенных ответов отлично работают на тестовой строке, однако результаты очень интересны для большого / реального файла, подробнее см. ниже.

Основываясь на приведенной выше тестовой строке, я сравнил ответы @Pavel Lint и @Toto. Ответ @Pavel Lint несколько быстрее, примерно в 10 раз в миллисекундах.

@ Pavel Lint
^.+Severity: 20.*\R^.*\R(?![\s\S]*Severity: 20)
1588 шагов, в среднем 2ms

@ Toto
[\s\S]+\K^.*?Severity: 20.*\R.*
61955 шагов, в среднем 36 мс

Однако , результаты в реальном файле сильно отличаются. Теперь я не могу предоставить файл, который я использовал для тестирования, так как это файл журнала клиента, поэтому я не ошибаюсь @Pavel Lint для ответа, так как он отлично работает на тестовой строке. Возможно, в моем вопросе было недостаточно ясного о том, над чем нужно работать в дикой природе, однако я утверждал, что «в дикой природе может быть любое количество вхождений в одном документе», что Я полагаю, что охватывает сценарий ios, в котором мы хотим избежать катастрофического возврата c.

Файл теста содержит 26 192 строки и 1595 появлений ошибки «Серьезность: 20» (соответствует шаблону, показанному в тесте строка, однако сообщение во второй строке будет другим и может содержать любое слово / число / специальные символы).

Первое приведенное выше регулярное выражение из @Pavel Lint убило Notepad ++, когда я его запустил.
Мое полуобразованное предположение состоит в том, что произошел катастрофический откат c.

Второе регулярное выражение из @Toto почти мгновенно совпало с последним вхождением.

В конечном счете, ответ @ Toto медленнее для небольших выборок, но масштабируется до очень больших файлов с множеством возможных совпадений.

Ответы [ 2 ]

1 голос
/ 29 января 2020
  • Ctrl + F
  • Найти что: [\s\S]+\K^.*?Severity: 20.*\R.*
  • CHECK Wrap вокруг
  • CHECK Регулярное выражение
  • UNCHECK . matches newline
  • Найти следующее

Объяснение:

[\s\S]+             # 1 or more any character
\K                  # forget all we have seen until this position
^                   # beginning of line
  .*?               # 0 or more any character but newline, not greedy
  Severity: 20      # literally
  .*                # 0 or more any character but newline
  \R                # any kind of linebreak
  .*                # 0 or more any character but newline

Снимок экрана:

enter image description here

1 голос
/ 29 января 2020

Я смог достичь того, что вы хотите, с помощью этого регулярного выражения:

^.+Severity: 20.*\R^.*\R(?![\s\S]*Severity: 20)

Это почти та же идея, которую вы изначально предложили, но в блоке с отрицательным прогнозом я заменил .* на [\s\S]*, чтобы он работал для новых строк.

Вот демоверсия: https://regex101.com/r/XWWFYc/1/

...