PCRE Regex - Как вернуть совпадения с многострочной строкой, ища несколько строк в любом порядке

Мне нужно использовать Perl-совместимое регулярное выражение для сопоставления нескольких строк, которые появляются в нескольких строках в файле.

Совпадения должны появляться в любом порядке (сервер servernameA.company.com, за которым следует servernameZ.company.com, затем servernameD.company.com или любая комбинация из трех). Примечание. Все совпадения будут отображаться в начале каждой строки.

В моем тестировании с grep -P я даже не смог найти совпадение для простых строковых терминов, которые появляются в любом порядке на новых строках (даже при использовании модификаторов /s и /m). Из прочитанного я почти уверен, что мне нужно предварительное утверждение, но образцы, которые я использовал, не дали мне совпадения даже после анализа каждого бита регулярного выражения, чтобы убедиться, что он соответствует моему сценарию.

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

Пример ввода

irrelevant_directive = 0

# Comment
server servernameA.company.com iburst

additional_directive = yes

server servernameZ.company.com iburst
server servernameD.company.com iburst

# Additional Comment
final_directive = true

Ожидание

Регулярное выражение должно соответствовать и возвращать 3 строки, начинающиеся с сервера (которые появляются в любом порядке), если и только если есть идеальное совпадение для строк «serverA.company.com», «serverZ.company.com» и «serverD». company.com», за которым следует iburst. Все 3 строки должны быть включены.

Наконец, если ответ (или очень похожая форма ответа) может адресовать проверку строк в любом порядке в одной строке, это было бы очень полезно. Например, если у меня есть однострочная строка: preauth param audit=true silent deny=5 severe=false unlock_time=1000 time=20ms, и я хочу, чтобы термины deny=5 и time=20ms отображались в любом порядке и, если так, совпадают.

Спасибо заранее за помощь.


person Kurt W    schedule 03.11.2016    source источник
comment
Вы говорите о PCRE или о программе Perl?   -  person simbabque    schedule 04.11.2016
comment
Спасибо за быстрый ответ и просмотр этого. ПКРЕ конкретно. Я буду использовать команду с grep -P. Пожалуйста, обновите, так как я добавил новый короткий раздел об ожидаемом выводе регулярного выражения, который я ранее пропустил.   -  person Kurt W    schedule 04.11.2016
comment
Тогда, пожалуйста, не помечайте Perl. Я удалю тег. Для этого есть решения с помощью полноценной программы, но сделать это в одном регулярном выражении будет сложно.   -  person simbabque    schedule 04.11.2016


Ответы (2)


Относительно основного вопроса [для второстепенного вопроса см. ответ Казимира и Ипполита] (с использованием модификатора x): https://regex101.com/r/mkxcap/5

(?:
  (?<a>.*serverA\.company\.com\s+iburst.*)
 |(?<z>.*serverZ\.company\.com\s+iburst.*)
 |(?<d>.*serverD\.company\.com\s+iburst.*)
 |[^\n]*(?:\n|$)
)++
(?(a)(?(z)(?(d)(*ACCEPT))))(*SKIP)(*F)

Теперь все совпадения находятся в группах захвата a, z и d.

Это не самый эффективный способ (он проходит три раза по каждой строке с откатом...), но основной вывод состоит в том, чтобы регистрировать совпадения с группами захвата, а затем проверять их определение.

person bwoebi    schedule 07.11.2016
comment
Спасибо, что предоставили это. Я поместил свой образец текста из исходного вопроса в файл и попробовал это регулярное выражение, но оно не возвращает хит. grep -P '(?:(?<a>.*serverA\.company\.com\s+iburst.*)|(?<z>.*serverZ\.company\.com\s+iburst.*)|(?<d>.*serverD\.company\.com\s+iburst.*)|[^\n]*(?:\n|$))++(?(a)(?(z)(?(d)(*ACCEPT))))(*SKIP)(*F)' testing ничего не возвращает. Это требует небольшой настройки? Если бы я мог гарантировать, что 3 строки всегда будут появляться сразу друг за другом (а не где-то по всему файлу), упростило бы это регулярное выражение? Заранее спасибо!! - person Kurt W; 07.11.2016
comment
@KurtW Проблема с grep -P заключается в том, что он соответствует строке за строкой отдельно. Вы не можете сопоставить что-либо, занимающее несколько строк, с помощью grep -P. Вам нужно скормить PCRE здесь весь файл. (процитируйте справочную страницу для grep: Получить шаблоны из ФАЙЛА, по одному в строке.) - person bwoebi; 08.11.2016

Вам не нужно использовать функции PCRE, вы можете просто написать в ERE:

grep -E '.*(\bdeny=5\b.*\btime=20ms\b|\btime=20ms\b.*\bdeny=5\b).*' file

Подход PCRE будет другим: (однако вы также можете использовать предыдущий шаблон)

grep -P '^(?=.*\bdeny=5\b).*\btime=20ms\b.*' file
person Casimir et Hippolyte    schedule 03.11.2016
comment
Привет Казимир! На самом деле это был мой второстепенный вопрос, на который вы ответили. Спасибо, это полезно, но есть ли у вас подход к решению основной проблемы (многострочный)? Извините, если я сделал вещи более запутанными, чем необходимо. Однострочное регулярное выражение было бонусом, и сейчас я его тестирую! - person Kurt W; 04.11.2016
comment
Привет, Казимир, я подтвердил, что твое решение однострочной проблемы работает отлично! Спасибо. Когда у вас будет возможность, вы не могли бы взглянуть на мой главный вопрос? Извините, что сгруппировал два в один - я не буду этого делать в будущем. - person Kurt W; 04.11.2016
comment
Проголосовал, так как это полезно. bwoebi решил мой основной вопрос. Спасибо за ваше время! - person Kurt W; 08.11.2016