Многострочное регулярное выражение с открывающим и закрывающим словом

#regex #multiline

Вопрос:

Я должен признать, что я очень прост, если дело доходит до выражений регулярных выражений. У меня есть приложение, написанное на C#, которое ищет определенные выражения регулярных выражений в текстовых файлах. Я не уверен, как объяснить свою проблему, поэтому перейду прямо к примеру.

Мое сообщение:

    DeviceNr : 30
     DeviceClass = ABC
     UnitNr = 1
     Reference = 29
     PhysState = ENABLED
    LogState = OPERATIVE
     DevicePlan = 702
     Manufacturer = CDE
     Model = EFG
    ready
    
    DeviceNr : 31
     DeviceClass = ABC
     UnitNr = 9
     Reference = 33
     PhysState = ENABLED
    LogState = OPERATIVE
     Manufacturer = DDD
     Model = XYZ
    Description = something here
    ready
 

Мне нужно сопоставить многострочный текст, который начинается со слова «DeviceNr», заканчивается «готово» и имеет «DeviceClass = ABC» и «Модель = XYZ» — я могу только предположить, что эти строки будут в таком точном порядке, но я не могу предположить, что будет между ними, даже количество других строк между ними. Я попытался использовать приведенное ниже регулярное выражение, но оно соответствовало всему тексту, а не только DeviceNr : 31

 DeviceNr : ([0-9] )(?:.*?n)*? DeviceClass = ABC(?:.*?n)*? Model = XYZ(?:.*?n)*?readynn
 

Комментарии:

1. Это то, что ты ищешь? (?=(DeviceNr.*?ready)) Демо: regex101.com/r/nZj7wS/2

2. Может быть, глупый вопрос, но как насчет той части, где мне нужно сопоставить строки «DeviceClass = ABC» и «Модель = XYZ» между «DeviceNr» и «готово» ?

3. Проверьте это: (?=DeviceNr.*?(DeviceClasss=sw ).*?(Models=sw ).*ready) Демонстрация: regex101.com/r/nZj7wS/3

4. Это все еще не дает мне того, в чем я нуждаюсь. regex101.com/r/MBXSht/1 Мне нужно, чтобы это было только одно совпадение (второе), мне нужно знать, что я сопоставил обе строки и что они помещены в «DeviceNr» и ПЕРВОЕ найденное «готовое» слово.

Ответ №1:

Если вы знаете, что "DeviceClass = ABC" and "Model = XYZ" они присутствуют и в таком порядке, вы также можете использовать утверждение lookahead для каждой строки, сначала сопоставляя все строки, которые, например, не содержат DeviceNr

Затем сопоставьте строки, которые это делают, а также сделайте это для Model и ready

 ^s*DeviceNr : ([0-9] )(?:r?n(?!s*DeviceClass =).*)*r?ns*DeviceClass = ABCb(?:r?n(?!s*Model =).*)*r?ns*Model = XYZb(?:r?n(?!s*ready).*)*r?ns*readyb
 
  • ^ Начало строки
  • s*DeviceNr : ([0-9] ) Сопоставьте DeviceNr : и зафиксируйте 1 цифры 0-9 в группе 1
  • (?: Группа без захвата
    • r?n(?!s*DeviceClass =).* Сопоставьте новую строку и подтвердите, что строка не содержит DeviceClass =
  • )* Закройте группу без захвата и при необходимости повторите, так как вы не знаете, сколько там строк
  • r?ns*DeviceClass = ABCb Сопоставьте новую строку, необязательные символы пробелов и DeviceClass = ABC
  • (?:r?n(?!s*Model =).*)*r?ns*Model = XYZb Предыдущий подход также для Model =
  • (?:r?n(?!s*ready).*)*r?ns*readyb И тот же подход к ready

Демонстрация регулярных выражений

Обратите внимание, что s это также может соответствовать новой строке. Если вы хотите предотвратить это, вы также можете использовать [^Srn] для сопоставления символа пробела без новой строки.

Демонстрация регулярных выражений

введите описание изображения здесь

Комментарии:

1. Спасибо! и спасибо за объяснение, это очень сложный шаблон, но он делает то, что мне нужно.

Ответ №2:

Вопрос в том, что вы хотите, чтобы соответствовать ‘DeviceNr : 31’ следует ‘DeviceClass = АВС (возможно с одной из промежуточных символов), а затем модель’ = Хуг (опять же, возможно, с одной из промежуточных символов), затем «Готово» (опять же, возможно, с одной из промежуточных символов) , убедившись, что никто из лиц, выступающих персонажей на самом деле являются началом другого ‘DeviceNr разделе.

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

 (?:(?!DeviceNr)[sS])*?
 
  1. (?: — Начало группы без захвата
  2. (?!DeviceNr) — Утверждает, что следующие символы ввода не являются «DeviceNr»
  3. [sS] — Соответствует пробелу или символу без пробелов, т. е. любому символу
  4. ) конец группы без захвата
  5. *? не жадно сопоставляйте 0 или более символов до тех пор, пока следующий ввод не будет соответствовать «DeviceNr».

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

 DeviceNr : (d )n(?:(?!DeviceNr)[sS])*?DeviceClass = ABCn(?:(?!DeviceNr)[sS])*?Model = XYZn(?:(?!DeviceNr)[sS])*?ready
 

Смотрите Демонстрацию регулярных выражений

Группа захвата 1 будет иметь DeviceNr значение.

Важное Примечание

Приведенное выше регулярное выражение довольно дорого с точки зрения количества шагов, необходимых для выполнения, поскольку оно должно проверять отрицательное утверждение lookahead практически в каждой позиции символа, как только оно совпадет DeviceNr : (d ) .